36. polygons
— Polygon meshes.¶
This module defines the Polygons class, which can be used to describe discrete geometrical models consisting of polygons.
36.1. Classes defined in module polygons¶
- class polygons.Polygons(coords=None, elems=None, *, prop=None, check=True)[source]¶
Polygons is a discrete geometrical model consisting of polygons.
The Polygons class is implemented in a similar manner as the
Mesh
and :class`TriSurface` classes: the coordinates of all the vertices are collected in a singleCoords
array, and the ‘elements’ (polygons) are defined using indices into that array. While theMesh
and :class`TriSurface` classes store the elements in anElems
array (requiring a fixed plexitude for all elements), the Polygons class uses aVarray
so that the polygons can have a variable number of vertices.- Parameters:
coords (coords_like) – A 2-dim
Coords
(or data to initalize it) with the coordinates of all the vertices used to define the polygons.elems (
Varray
) – AVarray
(or data to initalize it) with the indices of the vertices that define each of the polygons. All values in elems should be in the range 0 <= value < len(coords).prop (int array_like, optional) – 1-dim int array with non-negative element property numbers. If provided,
setProp()
will be called to assign the specified properties.
Examples
A Polygons with a triangle and a square.
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> print(P.report()) Polygons: nnodes: 4, nelems: 2, nplex: min 3, max 4, eltype: polygon BBox: [0. 0. 0.], [1. 1. 0.] Size: [1. 1. 0.] Coords: [[0. 0. 0.] [1. 0. 0.] [1. 1. 0.] [0. 1. 0.]] Elems: Varray (nrows=2, width=3..4) [0 1 2] [0 1 2 3]
- property eltype¶
Return the element type of the Polygons.
- Returns:
str – Always ‘polygon’
- property shape¶
Return the shape of the
elems
Varray.
- nplex()[source]¶
Return the plexitude of the polygon elements.
Always returns None, as there is no fixed plexitude of the polygons.
- property plex¶
Return the plexitude of each of the elements
- ncoords()[source]¶
Return the number of points used to define the polygons.
This is the first dimension of the
coords
array.Notes
This may be different from the total number of vertices in all the polygons, as polygons may share some vertices.
See also size: The total number of vertices in all the polygons.
- property size¶
Return the total number of polygon vertices.
This is the total number of entries in the
elems
Varray.
- info()[source]¶
Return short info about the Mesh.
- Returns:
str – A string with info about the shape of the
coords
andelems
attributes.
- report(full=True)[source]¶
Create a report on the Mesh shape and size.
The report always contains the number of nodes, number of elements, plexitude, dimensionality, element type, bbox and size. If full==True(default), it also contains the nodal coordinate list and element connectivity table. Because the latter can be rather bulky, they can be switched off.
Note
NumPy normally limits the printed output. You will have to change numpy settings to actually print the full arrays.
- shallowCopy(prop=None)[source]¶
Return a shallow copy.
- Parameters:
prop (int array_like, optional) – 1-dim int array with non-negative element property numbers.
- Returns:
Polygons – A shallow copy of the Mesh, using the same data arrays for
coords
andelems
. Ifprop
was provided, the new Mesh can have other property numbers. This is a convenient method to use the same Mesh with different property attributes.
- classmethod triangleSelector(n)[source]¶
Return a selector to get triangle fan elements from polygons.
Examples
>>> Polygons.triangleSelector(5) array([[0, 1, 2], [0, 2, 3], [0, 3, 4]])
- classmethod edgeSelector(n)[source]¶
Return a selector to get edge elements from polygons.
Examples
>>> Polygons.edgeSelector(5) array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]])
- triangles(layout='fan')[source]¶
Return an Elems with the triangles of the polygons
layout = ‘fan’ | ‘strip’ | ‘edglen’
TODO: only ‘fan’ is implemented!
- edges(layout='fan')[source]¶
Return an Elems with the edges of the polygons
layout = ‘fan’ | ‘strip’ | ‘edglen’
TODO: only ‘fan’ is implemented!
- property vertices¶
Return all vertices of all polygons.
- Returns:
Coords – The coordinates of all vertices of all polygons, in the order of the
elems
data.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> P.vertices Coords([[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]])
- vectors()[source]¶
Return vectors along all edges of all polygons.
- Returns:
Coords – The vectors along all the edges of all polygons, in the order of the
elems
data. The vectors point from each vertex to the next vertex in the polygon.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> P.vectors() Coords([[ 1., 0., 0.], [ 0., 1., 0.], [-1., -1., 0.], [ 1., 0., 0.], [ 0., 1., 0.], [-1., 0., 0.], [ 0., -1., 0.]])
- vectorPairs()[source]¶
Compute vector pairs along the edges at each vertex of the polygons.
- Returns:
vec1 (float array (nel, nplex, 3)) – The vectors from each vertex to the previous vertex in the polygon.
vec2 (float array (nel, nplex, 3)) – The vectors from each vertex to the next vertex in the polygon.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> v1, v2 = P.vectorPairs() >>> print(v1) [[-1. -1. 0.] [ 1. 0. 0.] [ 0. 1. 0.] [ 0. -1. 0.] [ 1. 0. 0.] [ 0. 1. 0.] [-1. 0. 0.]] >>> print(v2) [[ 1. 0. 0.] [ 0. 1. 0.] [-1. -1. 0.] [ 1. 0. 0.] [ 0. 1. 0.] [-1. 0. 0.] [ 0. -1. 0.]]
- property vnormals¶
Return normals at vertices of polygons.
- Returns:
normals (float array (self.size,3)) – The unit normals on the two edges ending at each vertex.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> n = P.vnormals >>> print(n.round(2)+0.) [[0. 0. 1.] [0. 0. 1.] [0. 0. 1.] [0. 0. 1.] [0. 0. 1.] [0. 0. 1.] [0. 0. 1.]]
- property angles¶
Compute internal angles at vertices of polygons.
- Returns:
angles (float array (nel, nplex)) – The internal angles made by the two polygon edges at the vertex.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3]]) >>> a = P.angles >>> print(a) [45. 90. 45. 90. 90. 90. 90.]
- property fnormals¶
Compute mean face normals of polygons.
- Returns:
fnormals (float array (self.nelems, 3)) – For each polygon, the mean of the normals at all its vertices.
Examples
>>> P = Polygons(Coords('0123'), [[0,1,2], [0,1,2,3], [2,1,0]]) >>> f = P.fnormals >>> print(f) [[ 0. 0. 1.] [ 0. 0. 1.] [ 0. 0. -1.]]
- avg_normals(weights='angle', full=False, treshold=None)[source]¶
Compute averaged normals at the nodes of a Polygons.
- Parameters:
coords (float array_like (ncoords, 3)) – Array with the coordinates of the nodes
elems (int array_like (nelems, nplex, 3)) – Definitions of the polygons in terms of the nodes. All polygons should have the same plexitude.
weights (float array_like | ‘angle’ | None) – Weights to apply to the polygon normals at a node during averaging. The default ‘angle’ will weigh the contribution of the polygons by the angle their edges make at the node. Custom values should be an array with shape (nelems, nplex). Specifying None will result in giving the same weight to all normals.
full (bool, optional) – If False (default), unique averaged normals at the nodes are returned. If True, the averaged normals are returned for each vertex of each polygon. This is mainly intended for rendering purposes.
treshold (float, optional) – Only used with
full=True
. If provided, element vertex normals making an angle with the averaged normal having a cosinus smaller than treshold, will be returned as the original normal. This allows the rendering of feature edges.
- Returns:
normals (float array) – (ncoords, 3) The unit normals at the nodes, obtained by (weighted) averaging the normals on the polygons attached to that node. The default
full=False
returns an array with shape (ncoords, 3). Withfull=True
, an array with shape (nelems, nplex, 3) is returned.
Examples
This example is the surface of a unit cube. Notice that the average normals come out nicely symmetric, even without weights, because all polygons have the same angles at the nodes.
>>> from pyformex.simple import Cube >>> M = Cube() >>> P = Polygons(M.coords, M.elems) >>> print(P.avg_normals()) [[-0.5774 -0.5774 -0.5774] [ 0.5774 -0.5774 -0.5774] [ 0.5774 0.5774 -0.5774] [-0.5774 0.5774 -0.5774] [-0.5774 -0.5774 0.5774] [ 0.5774 -0.5774 0.5774] [ 0.5774 0.5774 0.5774] [-0.5774 0.5774 0.5774]] >>> print(P.avg_normals(weights=None)) [[-0.5774 -0.5774 -0.5774] [ 0.5774 -0.5774 -0.5774] [ 0.5774 0.5774 -0.5774] [-0.5774 0.5774 -0.5774] [-0.5774 -0.5774 0.5774] [ 0.5774 -0.5774 0.5774] [ 0.5774 0.5774 0.5774] [-0.5774 0.5774 0.5774]]
- classmethod concatenate(polys)[source]¶
Concatenate a list of Polygons.
- Parameters:
polys (list of Polygons) – A list of Polygons instance to be concatenated to a single one.
Notes
The concatenation itself does not fuse the vertices that happen to be (nearly) conincident. You may want to call the
fuse()
method.If any of the Polygons has property numbers, the resulting Polygons will inherit the properties. In that case, any elements from Polygons without properties will be assigned property 0. If all input objects are without properties, so will be the result.
Examples
>>> M0 = Mesh(eltype='quad4') >>> P0 = Polygons(M0.coords, M0.elems) >>> P1 = Polygons(M0.coords.trl(0, 1.), [[0,1,2],[0,2,3]]) >>> P = Polygons.concatenate([P0,P1]) >>> print(P.coords) [[0. 0. 0.] [1. 0. 0.] [1. 1. 0.] [0. 1. 0.] [1. 0. 0.] [2. 0. 0.] [2. 1. 0.] [1. 1. 0.]] >>> print(P.elems) Varray (nrows=3, width=3..4) [0 1 2 3] [4 5 6] [4 6 7] >>> P = P.fuse() >>> print(P.coords) [[0. 0. 0.] [0. 1. 0.] [1. 0. 0.] [1. 1. 0.] [2. 0. 0.] [2. 1. 0.]] >>> print(P.elems) Varray (nrows=3, width=3..4) [0 2 3 1] [2 4 5] [2 5 3]
- fuse(nodes=None, **kargs)[source]¶
Fuse the nodes of a Polygons.
Nodes that are within the tolerance limits of each other are merged into a single node.
- Parameters:
nodes (int array_like, optional) – A list of node numbers. If provided, only these nodes will be involved in the fuse operation.
**kargs – Extra arguments for tuning the fuse operation are passed to the
coords.Coords:fuse()
method.Examples (see
concatenate()
) –
- compact()[source]¶
Remove unconnected nodes and renumber the Polygons.
- Returns:
Polygons – The input object, where any unconnected nodes have been removed and the nodes are renumbered to a compacter scheme.
Notes
This changes the object in-place.
If the node-numbering has been changed, the object will have an attribute ‘oldnumbers’ which is an int array giving the old node number for in the position of the new node number.
Examples
>>> x = Coords([[i] for i in np.arange(5)]) >>> P = Polygons(x, [[0,1,2],[2,3,1,0]]) >>> print(P.coords) [[0. 0. 0.] [1. 0. 0.] [2. 0. 0.] [3. 0. 0.] [4. 0. 0.]] >>> P1 = P.compact() >>> print(P1.coords) [[0. 0. 0.] [1. 0. 0.] [2. 0. 0.] [3. 0. 0.]] >>> print(P1.elems) Varray (nrows=2, width=3..4) [0 1 2] [2 3 1 0] >>> P1 is P True >>> print(P.oldnumbers) None >>> P = Polygons(x, [[4,1,2],[2,3,1,4]]) >>> P.compact() <pyformex.polygons.Polygons object at ...> >>> print(P.coords) [[1. 0. 0.] [2. 0. 0.] [3. 0. 0.] [4. 0. 0.]] >>> print(P.elems) Varray (nrows=2, width=3..4) [3 0 1] [1 2 0 3] >>> print(P.oldnumbers) [1 2 3 4]
- reduce(mplex)[source]¶
Reduce the Polygons to a specified maximum plexitude.
- Parameters:
mplex (int) – The maximal plexitude of the output polygons. Thus, with mplex=3 only triangles will results; mplex=4 will yield triangles and quads.
- Returns:
Polygons – A Polygons where all of the polygons with more than mplex vertices have been split into smaller ones.
Notes
Splitting a polygon is done along the shortest diagonal.
See also
split
split (and optionally reduce) the Polygons into Mesh objects.
Examples
>>> x = Coords([[i] for i in np.arange(5)]) >>> P = Polygons(x, [[0,1,2],[0,1,2,3],[0,1,2,3,4]]) >>> print(P.reduce(4).elems) Varray (nrows=4, width=3..4) [0 1 2] [0 1 2] [0 1 2 3] [2 3 4 0] >>> print(P.reduce(3).elems) Varray (nrows=6, width=3..3) [0 1 2] [0 1 2] [0 1 2] [2 3 4] [2 3 0] [4 0 2] >>>
- split(mplex=None)[source]¶
Split the Polygons into Meshes of fixed plexitude
- Parameters:
mplex (int, optional) – The maximal plexitude of the resulting Meshes. Thus, with mplex=3 only triangles will results; mplex=4 will yield triangles and quads. If needed, polygons will be split up to be smaller that the maximum plexitude. If not provided, the original plexitudes are kept.
- Returns:
list of Mesh – A list of Mesh objects with plexitude >= 3. The eltype of the Mesh objects is Tri3, Quad4 or Poly# for plexitudes > 4. All the Mesh objects use the same coords object. The list is sorted in order of increasing plexitude.
Notes
While reducing and splitting the Polygons can also be achieved with
self.reduce(mplex).split()
, using the mplex argument here is slightly faster.See also
reduce
reduce the maximum plexitude of the polygons
- toSurface(method='reduce')[source]¶
Convert the Polygons to a TriSurface
- Parameters:
method (str) –
The method to use to convert polygons into triangles. One of:
’reduce’: use the
reduce()
method, splitting the polygons along the shortest diagonals. This is the default.’fan’: split the polygons into a fan of triangles with apex at the first point. This corresponds to hoe the polygons are rendered.
’prune’: simply removes all non-triangle polygons.
Notes
Currently, the ‘reduce’ method does not retain the ‘prop’ values.
36.2. Functions defined in module polygons¶
- polygons.nodalVSum(val, elems, nnod=None)[source]¶
Compute the nodal sum of values defined at polygon vertices.
This is like
arraytools.nodalSum()
, but where elems is defined as a Varray and val contains the value in order of that Varray.- Parameters:
- Returns:
sum (float ndarray (nnod, nval)) – The sum of all the values at the same node.
cnt (int ndarray (nnod)) – The number of values summed at each node.