44. trisurface — Operations on triangulated surfaces.

A triangulated surface is a surface consisting solely of triangles. Any surface in space, no matter how complex, can be approximated with a triangulated surface.

44.1. Classes defined in module trisurface

class trisurface.TriSurface(*args, prop=None, **kargs)[source]

A class representing a triangulated 3D surface.

A triangulated surface is a surface consisting of a collection of triangles. The TriSurface is subclassed from Mesh with a fixed plexitude of 3. The surface contains ntri triangles and nedg edges. Each triangle has 3 vertices with 3 coordinates. The total number of vertices is ncoords.

Parameters:
  • args

    Data to initialize the TriSurface. This can be 1, 2 or 3 arguments specifying one the the following data sets:

    • an (ntri,3,3) array_like specifying the coordinates of the vertices of the triangles,

    • a Formex with plexitude 3,

    • a Mesh with plexitude 3,

    • an (ncoords,3) coords_like with the vertex coordinates and an (ntri,3) int array_like specifying three vertex indices for each of the triangles

    • an (ncoords,3) coords_like with the vertex coordinates, an (nedg,2) int array_like specifying the vertex inidices of the edges, and an (ntri,3) int array_like specifying the edge indices of the triangles.

  • prop (int array_like, optional) – This keyword argument can be used to attribute property values to the elements of the TriSurface, like in the Mesh class.

See also

TriSurface.read

read a TriSurface from file

Formex.toSurface

convert a Formex to a TriSurface

Mesh.toSurface

convert a Mesh to a TriSurface

Examples

This example is a unit square divided in two triangles with the following following layout and numbering of nodes(n), elements(e) and edges:

n3      4    n2
  o---------o
  |        /|
  |  e1   / |
  |      /  |
  |     /   |
 2|    /1   |3
  |   /     |
  |  /      |
  | /   e0  |
  |/        |
  o---------o
n0     0     n1
>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> print(S)
TriSurface: nnodes: 4, nelems: 2, nplex: 3, level: 2, eltype: tri3
  BBox: [0. 0. 0.], [1. 1. 0.]
  Size: [1. 1. 0.]
  Length: 4.0  Area: 1.0
>>> print(S.coords)
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> print(S.elems)
[[0 1 2]
 [2 3 0]]
>>> print(S.nedges(), S.nfaces())
5 2
>>> print(S.edges)
[[0 1]
 [2 0]
 [3 0]
 [1 2]
 [2 3]]
>>> print(S.elem_edges)
[[0 3 1]
 [4 2 1]]
nedges()[source]

Return the number of edges of the TriSurface.

Note

As a side-effect, this computes and stores the edges and elem_edges arrays. The returned value is the first dimension of self.edges.

nfaces()[source]

Return the number of faces of the TriSurface.

Note

As a side-effect, this computes and stores the edges and elem_edges arrays. The returned value is the first dimension of self.elem_edges. Use self.nelems() to get the number of faces without having the side effect.

vertices()[source]

Return the coordinates of the nodes of the TriSurface.

Note

The direct use of the coords is prefered over this method.

shape()[source]

Return the number of points, edges, faces of the TriSurface.

Returns:

  • ncoords (int) – The number of vertices

  • nedges (int) – The number of edges

  • nfaces – The number of faces

set_coords(coords)[source]

Change the coords.

set_elems(elems)[source]

Change the elems.

set_edges_faces(edges, faces)[source]

Change the edges and faces.

append(S)[source]

Merge another surface with self.

Notes

This just merges the data sets, and does not check whether the surfaces intersect or are connected! This is intended mostly for use inside higher level functions.

classmethod read(fn, ftype=None, convert=False)[source]

Read a surface from file.

Parameters:
  • fn (path_like) –

    The pathname of the file to be read. The name suffix normally normally specifies the file type. Currently the following file types can be read:

    • obj, off, ply (polygon formats)

    • gts (libgts format)

    • stl (ascii or binary)

    • neu (Gambit neutral)

    • smesh (tetgen)

    • vtk, vtp (vtk formats)

    Compressed files for the polygon, gts and stl formats are also supported, if they are compressed with gzip or bzip2 and have an extra name suffix ‘.gz’ or ‘.bz2’, respectively. These files are transparently decompressed during reading. This allows for a very efficient use of storage space for large models.

  • ftype (str, optional) – Specifies the file type. This is (only) needed if the filename suffix does not specify the file type.

Examples

>>> S = TriSurface.read(pf.cfg['datadir'] / 'horse.off')
>>> print(S)
TriSurface: nnodes: 669, nelems: 1334, nplex: 3, level: 2, eltype: tri3
  BBox: [-0.0918 -0.0765 -0.0422], [0.0925 0.0777 0.0428]
  Size: [0.1843 0.1542 0.085 ]
  Length: 0.0  Area: 0.03646  Volume: 0.0002634
write(fn, ftype=None, *, name=None, binary=False, color=None, **kargs)[source]

Write the surface to file.

Parameters:
  • fn (path_like) – The output file name. The suffix will determine the file format, unless explicitely specified by ftype. Available formats are: ‘pgf’, ‘gts’, ‘off’, ‘stl’, ‘stla’, ‘stlb’, ‘obj’, ‘smesh’, ‘vtp’, ‘vtk’. If there is no suffix, ‘off’ format is used. For most file formats, an extra ‘.gz’ or ‘.bz2’ suffix can be added to have the file transparently be compressed by ‘gzip’ or ‘bzip2’, respectively.

  • ftype (str, optional) – The output file format. If not provided, it is determined from the filename suffix. For a ‘stl’ types, ftype may be set to ‘stla’ or ‘stlb’ to force ascii or binary STL format.

  • name (str, optional) – A name for the model that will be written into the output file if it is a ‘pgf’ or ‘obj’ format.

  • binary (bool) – If True, use binary format when the file format supports it. This is only useful if the file format supports both ascii and binary formats (currently ‘ply’ and ‘stl’).

  • color (color_like) – The color of the object to be written in case of a binary stl type (see also notes).

  • kargs – Extra keyword arguments to be passed to the writer.

Notes

If the surface has ‘color’ in its Attributes, the color will be written to the file in the case of the formats: ‘pgf’, ‘stlb’, ‘stl’ with binary=True.

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> with utils.TempDir() as dir:
...     fn = dir / 'test.off'
...     S.write(fn, name='Square')
...     print(fn.read_text())
Writing surface to file .../test.off (off)
Wrote 4 vertices, 2 faces
OFF
# OFF file written by pyFormex ...
# name=Square
4 2 0
0.0 0.0 0.0
1.0 0.0 0.0
1.0 1.0 0.0
0.0 1.0 0.0
3 0 1 2
3 2 3 0
areaNormals()[source]

Compute the area and normal vectors of the surface triangles.

Returns:

  • areas (ndarray) – A float (nelems,) shaped array with the areas of the triangles.

  • fnormals (ndarray) – A float (nelems, 3) shaped array with the normalized normal vectors on the triangles.

Notes

As a side-effect, the returned arrays are stored in the object, to avoid recalculation.

See also

areas

return only the areas

normals

return only the normals

avgVertexNormals

return averaged normals at the vertices

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> areas, normals = S.areaNormals()
>>> print(areas)
[0.5 0.5]
>>> print(normals)
[[0. 0. 1.]
 [0. 0. 1.]]
areas()[source]

Return the areas of the triangles.

Returns:

areas (ndarray) – A float (nelems,) shaped array with the areas of the triangles.

Notes

As a side-effect, the normals are computed as well and both are stored in the object, to avoid recalculation.

See also

area()

return the total area of the surface

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> print(S.areas())
[0.5 0.5]
normals()[source]

Return the normals on the triangles.

Returns:

normals (ndarray) – A float (nelems, 3) shaped array with the normalized normal vectors on the triangles.

Notes

As a side-effect, the areas are computed as well and both are stored in the object, to avoid recalculation.

See also

avgVertexNormals

return averaged normals at the vertices

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> print(S.normals())
[[0. 0. 1.]
 [0. 0. 1.]]
avgVertexNormals()[source]

Compute the average normals at the vertices.

TriSurfaces are often used as an approximation of a smooth surface. In such case, a more realistic rendering is obtained by using the average normals at the vertices instead of the facet normals. The normals are computed as the average of the normals on the faces connected to the node, using the angle between the edges as weights.

Returns:

normals (ndarray) – A float (ncoords, 3) shaped array with the normalized averaged normal vectors at the nodes.

See also

geomtools.polygonAvgNormals

the function used to compute the average normals and providing more options and examples.

Examples

The model is an octaeder having its vertices in the directions of the global axes.

>>> from pyformex import simple
>>> S = simple.sphere(0, base='octa')
>>> print(S.avgVertexNormals())
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]
 [-1.  0.  0.]
 [ 0. -1.  0.]
 [ 0.  0. -1.]]
volume()[source]

Return the enclosed volume of the surface.

This will only be correct if the surface is a closed manifold.

nodalWeights()[source]

Returns point weight based on adjacent area weight.

One third of the area of each triangle is attributed to each of its nodes, and the results are summed at the nodes.

Returns:

np.ndarray – Area based point weight array.

Examples

>>> from pyformex.simple import Cube
>>> S = Cube().convert('tri3-u').toSurface()
>>> print(S.nodalWeights())
[1.     0.6667 0.6667 0.6667 0.6667 0.6667 1.     0.6667]
>>> print(S.nodalWeights().sum())
6.0
inertia(model='C', density=1.0, totalmass=None)[source]

Return inertia related quantities of the surface.

Parameters:
  • model ('C' | 'W' | 'X' | 'A' | 'V') –

    Defines how the mass is distributed over the model.

    • ’C’: The mass of each triangle is concentrated at the centroid of the triangle. This is the default.

    • ’W’: The mass of each triangle is concentrated at the nodes of the triangles, attributing ont third to each.

    • ’X’: The mass is concentrated at the nodes, attributing an equal share of the total mass to each of them.

    • ’A’: The mass is evenly distributed over the triangles. This is currently not implemented!

    • ’V’, the mass is evenly distributed over the volume inside the surface.

  • density (float) – A constant density (mass per unit area, or mass per unit volume with model='V'. This allows the returned inertia values to be realistic.

Returns:

Inertia – An Inertia instance with the following attributes:

  • mass: the total mass (float)

  • ctr:: the center of mass: float (3,)

  • tensor: the inertia tensor in the central axes: shape (3,3)

Notes

The ‘A’ model is currently not implemented. The ‘C’ model neglects the inertia of each triangle around its own centroid.

It is currently not possible to specify variable density.

Examples

This is an approximation of a spherical surface with radius R=1. A perfect spherical surface with density 1 has a mass M = 4 πR^2 = 12.566... and a rotational inertia 2/3 MR^2 = 8.377....

>>> from pyformex.simple import sphere
>>> S = sphere(8)
>>> I = S.inertia()
>>> print(I.mass)
12.50...
>>> print(I.tensor)
[[ 8.2735  0.     -0.    ]
 [ 0.      8.2735  0.    ]
 [-0.      0.      8.2735]]

The results are smaller than the theoretical, because the nodes are on the sphere, but the triangle centroids are slightly inside. Therefore, concentrating the mass at the nodes gives better results.

>>> I = S.inertia(model='X')
>>> print(I.mass)
12.50...
>>> print(I.tensor)
[[ 8.3375  0.     -0.    ]
 [ 0.      8.3375  0.    ]
 [-0.      0.      8.3375]]

Let’s use an area-equivalent spherical approximation instead: this has the nodes slightly outside the sphere and the centroids inside. As expected, it delivers the correct mass.

>>> SA = sphere(8, equiv='A')
>>> I = SA.inertia()
>>> print(I.mass)
12.566...
>>> print(I.tensor)
[[ 8.3533 -0.     -0.    ]
 [-0.      8.3533 -0.    ]
 [-0.     -0.      8.3533]]

Considered as a volume, the mass of a perfect sphere is 4/3 πR^2 = 4.188… and the inertia is 2/5 MR^2 = 1.675….

>>> I = S.inertia(model='V')
>>> print(I.mass)
4.1526...
>>> print(I.tensor)
[[ 1.6515  0.     -0.    ]
 [ 0.      1.6515 -0.    ]
 [-0.     -0.      1.6515]]

With a volume-equivalent model, we get:

>>> SV = sphere(8, equiv='V')
>>> I = SV.inertia(model='V')
>>> print(I.mass)
4.188...
>>> print(I.tensor)
[[ 1.6755 -0.      0.    ]
 [-0.      1.6755 -0.    ]
 [ 0.     -0.      1.6755]]
curvature(neigh=1)[source]

Compute curvature parameters at the nodes.

Parameters:

neigh (int) – The maximum number of edge steps allowed from a node to its neigbors to have them included in the node’s neigborhood.

Returns:

Namespace – An object with the following attributes:

  • S: the shape index

  • C: the curvedness

  • K: the Gaussian curvature

  • H: the mean curvature

  • k1: the first principal curvature

  • k2: the second principal curvature

  • d1: the first principal direction

  • d2: the second principal direction

Notes

Algorithms are based on Koenderink and Van Doorn, 1992 and Dong and Wang, 2005.

The shape index varies between -1 and +1 and classifies the surface as follows:

  concave     concave                   convex     convex
  ellipsoid   cylinder   hyperboloid    cylinder   ellipsoid
 +----------+----------+--------------+----------+----------+
-1        -5/8       -3/8            3/8        5/8         1
surfaceType()[source]

Check whether the TriSurface is a manifold, orientable and closed.

Returns:

  • manifold (bool) – True if the surface is a manifold

  • orientable (bool) – True if the surface is an orientable manifold

  • closed (bool) – True if the surface is a closed manifold

  • mincon (int) – The minimum number of triangles at any edge

  • maxcon (int) – The maximum number of triangles at any edge

See also

isManifold

check if a surface is a manifold

isOrientable

check if a surface is an orientable manifold

isClosedManifold

check if a surface is a closed manifold

Notes

A Möbius ring is an open non-orientable manifold. A Klein bottle is a closed non-orientable (self-intersecting) manifold.

Examples

>>> from pyformex import simple
>>> simple.sphere(4).surfaceType()
(True, True, True, 2, 2)
>>> simple.MoebiusRing().toSurface().surfaceType()
(True, False, False, 1, 2)
>>> from pyformex.examples.KleinBottle import KleinBottle
>>> S = KleinBottle().toSurface()
>>> S.surfaceType()
(True, True, False, 1, 2)
>>> S.fuse().surfaceType()
(True, False, True, 2, 2)
isManifold()[source]

Check whether the TriSurface is a manifold.

A surface is a manifold if for every point of the surface a small sphere exists that cuts the surface to a part that can continuously be deformed to an open disk.

Returns:

bool – True if the surface is a manifold.

isClosedManifold()[source]

Check whether the TriSurface is a closed manifold.

A closed manifold is a manifold where each edge has exactly two triangles connected to it.

Returns:

bool – True if the surface is a closed manifold.

isConvexManifold()[source]

Check whether the TriSurface is a convex manifold.

Returns:

bool – True if the surface is a convex manifold.

Examples

>>> from pyformex import simple
>>> simple.sphere(4).isConvexManifold()
True
isOrientable()[source]

Check whether the TriSurface is an orientable manifold.

A surface is an orientable manifold if it is a manifold and if for all edges where two triangles meet, the triangles have the two nodes in opposite order in their element definition. This also means that if the two triangles are rotated around the edge to fall in the same plane, with their third vertex at opposite sides of the edge, the triangles have the same positive normal.

Returns:

bool – True if the surface is orientable.

See also

amborientedEdges

list the edges where the normals are opposite

nonManifoldEdges()[source]

Return the non-manifold edges.

Non-manifold edges are edges having more than two triangles connected to them.

Returns:

int array – The indices of the non-manifold edges in a TriSurface. These indices refer to the list of edges as stored in edges.

nonManifoldEdgesFaces()[source]

Return the non-manifold edges and faces.

Non-manifold edges are edges that are connected to more than two faces.

Returns:

  • edges (int array) – The indices of the non-manifold edges.

  • faces (int array) – The indices of the faces connected to any of the non-manifold edges.

removeNonManifold()[source]

Remove the non-manifold edges.

Removes the non-manifold edges by iteratively applying removeDuplicate() and collapseEdge() until no edge has more than two connected triangles.

Returns:

TriSurface – The reduced surface.

amborientedEdges()[source]

Return the amboriented edges.

Amboriented edges are edges where two triangles are connected with different orientation, making the surface non-orientable.

Returns:

int array – The indices of the amboriented edges in a TriSurface.

Notes

This requires that the surface is a manifold. Non-manifold edges are also amboriented, but are not included in this list. An error is raised if there are non-manifold edges.

In a manifold surface there are only two triangles possible at an edge,and they should have the edge nodes numbered in different order for the surface to be orientable. Thus all the edges should come out as unique when permutations=’none’ is used in arraytools.uniqueRowsIndex(). The non-unique edges are the amboriented edges.

borderEdges()[source]

Find the border edges of a TriSurface.

Border edges are edges that belong to only one element.

Returns:

bool ndarray – An array of length self.nedges() that is True for the edges that are on the border of the surface.

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> print(S.borderEdges())
[ True False  True  True  True]
borderEdgeNrs()[source]

Returns the numbers of the border edges.

Returns:

int array – The indices of the border edges. These indices refer to the list of edges as stored in edges.

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> print(S.borderEdgeNrs())
[0 2 3 4]
borderNodeNrs()[source]

Detect the border nodes of TriSurface.

The border nodes are the vertices belonging to the border edges.

Returns:

int array – The indices of the border nodes.

checkBorder()[source]

Find the border contours of a TriSurface.

Returns:

list of Elems – A list of connectivity tables. Each table holds the subsequent line segments of one continuous contour of the border of the surface.

Examples

>>> S = Mesh(eltype='quad4').convert('tri3-u').toSurface()
>>> S.checkBorder()
[Elems([[0, 1],
       [1, 2],
       [2, 3],
       [3, 0]], eltype=Line2)]
border(compact=True)[source]

Return the border meshes of a TriSurface.

Parameters:

compact (bool) – If True (default), the returned meshes are compacted. Setting compact=False will return all Meshes with the full surface coordinate sets. This is e.g useful for filling the border and merging the result with the original surface.

Returns:

list of Mesh – The complete border of the surface is returned as a list of plex-2 Meshes. Each Mesh constitutes a continuous part of the border.

fillBorder(method='radial', dir=None, compact=True)[source]

Fill the border areas of a surface.

Parameters:
  • method (str) – One of the methods accepted by the fillBorder() function: ‘radial’, ‘border’ or ‘planar.

  • dir ((3,) array_like, optional) – Only used with method='planar': the projection direction. See fillBorder().

  • compact (bool) – If True (default), the returned surfaces are compacted. If False, they still retain all the nodes of the original surface.

Returns:

list of TriSurface – The list of surfaces that fill all the border contours of the input surface as obtained by :meth:border’. If the surface is initially closed, an empty list is returned.

The surfaces will have property values higher than those of the parent surface. Thus, if they are added to the surface to close the holes in it, the different parts can still be identified.

See also

close

closes the surface by adding the border fills

trisurface.fillBorder()

fill a contour with a TriSurface

close(method='radial', dir=None)[source]

Close all the holes in a surface.

Computes the hole filling surfaces and adds them to the surface to make it a closed surface. Parameters are like for fillBorder().

Returns:

TriSurface – A TriSurface which is the merging of the input surface with the surfaces returned by fillBorder().

See also

fillBorder

compute the hole filling surfaces

edgeLengths()[source]

Returns the lengths of all edges

Returns:

float array – The length of all the edges, in the order of Mesh.edges.

Notes

As a side effect, this computes and stores the connectivities of the edges to nodes and of the elements to edges in the attributes edges, resp. elem_edges.

edgeAngles(return_mask=False)[source]

Return the signed angles over all edges.

The edge angles are the angles between the faces connected to that edge. It is the angle between the 2 face normals. The surface should be a manifold (having max. 2 faces per edge). The returned angles are in degrees in the range ]-180, 180]. The sign of the angle determines the convexity of the surface over that edge:

  • angle < 0: concave

  • angle = 0: flat

  • angle > 0: convex

  • angle = 180: folded

Parameters:

return_mask (bool) – If True, also returns the mask of edges connecting two faces.

Returns:

  • angles (float array) – An array with for each edge the angle between the normals on the two faces sharing that edge. For edges connected to only one element, a value 0 is returned.

  • mask (bool array) – True for the edges that connect two faces. Only returned if return_mask is True.

Notes

As a side effect, this method also sets the area, normals, elem_edges and edges attributes.

featureEdges(angle=60.0, minangle=None)[source]

Return the feature edges of the surface.

Feature edges are edges that are prominent features of the geometry. They are either border edges or edges where the normals on the two adjacent triangles differ more than a given value. The non feature edges then represent edges on a rather smooth surface.

Parameters:
  • angle (float) – The minimum value of the angle (in degrees) between the normals on two adjacent triangles in order for the edge to be considered a feature edge.

  • minangle (float, optional) – The maximum negative edge angle value for concave edges to be considered feature edges. If not specified, this is set equal to -angle.

Returns:

bool array – An array with shape (nedg,) where the feature edges are marked True. These are the edges where sel.edgeAngles() is outside the range [minangle, angle].

Notes

As a side effect, this also sets the elem_edges and edges attributes, which can be used to get the edge data with the same numbering as used in the returned mask. Thus, the following constructs a Mesh with the feature edges of a surface S:

p = S.featureEdges()
Mesh(S.coords,S.edges[p])
quality()[source]

Compute a quality measure for the triangle schapes.

The quality of a triangle is defined as the ratio of the square root of its surface area to its perimeter, divided by the same ratio for an equilateral triangle with the same area. The quality thus has a value 1.0 for an equilateral triangle and tends to 0.0 for a very stretched triangle.

Returns:

array – A float array with the quality of each of the triangles.

Examples

This model has four triangles with increasing shear. The first is an equilateral triangle. The last is the most obtuse.

>>> F = Formex('3:064')
>>> S = Formex.concatenate([F.shear(0,1,a).trl(0,2*a)
...     for a in [0.5, 1., 1.5, 2.]]
...     ).toSurface().scale([1., np.sqrt(3.)/2, 1.])
>>> print(S.areas())
[0.433 0.433 0.433 0.433]
>>> print(S.perimeters())
[3.     3.1889 3.7321 4.5023]
>>> print(S.aspectRatio())
[1.1547 2.0207 3.4641 5.4848]
>>> print(S.quality())
[1.     0.9408 0.8038 0.6663]
aspectRatio()[source]

Return the apect ratio of the triangles of the surface.

The aspect ratio of a triangle is the ratio of the longest edge over the smallest altitude of the triangle. Equilateral triangles have the smallest aspect ratio: 2/√3.

Returns:

array – A float array with the aspect ratio of each of the triangles.

See also

quality

compute a quality measure for triangular meshes

perimeters()[source]

Return the perimeters of all triangles.

Returns:

array – A float array with the perimeter of each of the triangles.

See also

quality

compute a quality measure for triangular meshes

smallestAltitude()[source]

Return the smallest altitude of the triangles of the surface.

longestEdge()[source]

Return the longest edge of the triangles of the surface.

shortestEdge()[source]

Return the shortest edge of the triangles of the surface.

stats()[source]

Return a text with full statistics about the surface.

distanceOfPoints(X, return_points=False, timeit=False)[source]

Find the distances of points X to the TriSurface.

The distance of a point is the minimum of: - the smallest perpendicular distance to any of the facets; - the smallest perpendicular distance to any of the edges; - the smallest distance to any of the vertices.

Parameters:
  • X (coords_like) – An (nX,3) shaped float array with the coordinates of nX points.

  • return_points (bool, optional) – If True, also returns an array with the closest points on the surface.

Returns:

  • dist (array) – A float array of length nX with the distance of the points to the surface.

  • footpoints (array) – Only returned if return_points = True: an array with shape (nX,3) holding the coordinates of the footpoints on the surface.

Examples

>>> from pyformex import simple
>>> S = simple.sphere()
>>> dist, pts = S.distanceOfPoints([[1,0,0], [1,1,0], [1,1,1]], True)
>>> dist
array([0.    , 0.4181, 0.7321])
>>> pts
Coords([[1.    , 0.    , 0.    ],
        [0.7199, 0.6896, 0.    ],
        [0.5774, 0.5774, 0.5774]])
degenerate()[source]

Return a list of the degenerate faces according to area and normals.

A triangle is degenerate if its area is less or equal to zero or the normal has a nan.

Returns:

int array – The sorted list of indices of the degenerate elements.

removeDegenerate(compact=False)[source]

Remove the degenerate elements from a TriSurface.

Parameters:

compact (bool, optional) – If True, the TriSurface is compacted after removing the degenerate elements.

Returns:

TriSurface – A TriSurface with all the degenerate elements removed. By default, the coords attribute is unaltered and will still contain all points, even ones that are no longer connected to any element. If compact=True, unused nodes are removed.

collapseEdge(edg)[source]

Collapse an edge in a TriSurface.

Collapsing an edge removes the triangles connected to the edge and replaces the two vertices of the edge with a single one, placed at the center of the edge. Triangles connected to one of the edge vertices, will become connected to the new vertex.

Parameters:

edg (int) – The index of the edg to be removed. This is an index in the edges array.

Returns:

TriSurface – An almost equivalent surface with the specified edge removed.

offset(distance=1.0)[source]

Offset a surface with a certain distance.

Parameters:

distance (float) – Distance over which the points should be moved.

Returns:

TriSurface – A TriSurface obtained by moving all the nodes of the input surface over the specified distance in the direction of the averaged normal vector.

dualMesh(method='median')[source]

Return the dual mesh of a compacted triangulated surface.

Creates a Quad4 Mesh where all elements with prop p represent the dual mesh region around the original surface node p.

Parameters:

method ('median' | 'voronoi') – The method to be used to create the dual mesh. The default ‘median’ connects the center of each triangle with the centers of its edges. The ‘voronoi’ method constructs domains where each point belongs to the closest node.

Returns:

Mesh – The dual Quad4 Mesh. The elements have property numbers equal to the node number around which they are based.

Examples

>>> S = Formex('3:.12').toSurface().subdivide(2)
>>> T = S.dualMesh()
>>> print(T.elems)
[[ 0  6 18  8]
 [ 1  7 18  6]
 [ 3  8 18  7]
 [ 1  9 19 11]
 [ 2 10 19  9]
 [ 4 11 19 10]
 [ 3 12 20 14]
 [ 4 13 20 12]
 [ 5 14 20 13]
 [ 1 15 21 17]
 [ 4 16 21 15]
 [ 3 17 21 16]]
>>> print(T.fuse().elems.listDegenerate())
[]
>>> T = S.dualMesh('voronoi')
>>> print(T.elems)
[[ 0  6 18  8]
 [ 1  7 18  6]
 [ 3  8 18  7]
 [ 1  9 19 11]
 [ 2 10 19  9]
 [ 4 11 19 10]
 [ 3 12 20 14]
 [ 4 13 20 12]
 [ 5 14 20 13]
 [ 1 15 21 17]
 [ 4 16 21 15]
 [ 3 17 21 16]]
>>> print(T.fuse().elems.listDegenerate())
[ 0  2  3  5  6  8  9 10]
partitionByAngle(angle=60.0, sort='number')[source]

Partition the surface by splitting it at sharp edges.

The surface is partitioned in parts in which all elements can be reached without ever crossing a sharp edge angle. More precisely, any two triangles will belong to the same part if the can be connected by a line in the surface that does not cross an edge between two elements having their normals differ more than the specified angle.

Parameters:
  • angle (float) – The minimum value of the angle (in degrees) between the normals on two adjacent triangles in order for the edge to be considered a sharp edge.

  • sort (str) –

    Defines how the resulting parts are sorted (by assigning them increasing part numbers). The following sort criteria are currently defined (any other value will return the parts unsorted):

    • ’number’: sort in decreasing order of the number of triangles in the part. This is the default.

    • ’area’: sort according to decreasing surface area of the part.

Returns:

int array – An int array specifying for each triangle to which part it belongs. Values are in the range 0..nparts.

Notes

In order for the operation to be non-trivial, the specified edges, possibly together with (parts of) the border, should form one or more closed loops.

Beware that the existence of degenerate elements may cause unexpected results. If unsure, use the removeDegenerate() method first to remove those elements.

cutWithPlane1(p, n, side='', return_intersection=False, atol=0.0)[source]

Cut a surface with a plane.

Cut the surface with a plane defined by a point p and normal n.

Warning

This is experimental and may not work correctly.

Parameters:
  • p (float array_like (3,)) – A point in the cutting plane.

  • n (float array_like (3,)) – The normal vector to the cutting plane.

  • side ('' | '+' | '-') – Selects the returned parts. Default (‘’) is to return a tuple of two surfaces, with the parts at the positive, resp. negative side of the plane, as defined by the normal vector. If a ‘+’ or ‘-’ is specified, only the corresponding part is returned.

Returns:

  • Spos (TriSurface, optional) – The part of the surfacec at the positive side of thr plane (p,n). Only returned if side is ‘’ or ‘+’.

  • Sneg (TriSurface, optional) – The part of the surfacec at the negative side of thr plane (p,n). Only returned if side is ‘’ or ‘-‘.

  • The returned surfaces have their normals fixed wherever possible.

  • Prop values are set containing the triangle number in the

  • original surface from which the elements resulted.

cutWithPlane(*args, **kargs)[source]

Cut a surface with a plane or a set of planes.

Cut the surface with one or more planes and return either one side or both. This uses a conversion to a 3-plex Formex to do the cutting, and then converts the results back to TriSurface(s). The parameters are the same as in Formex.CutWithPlane(). The returned surface(s) will have the normals fixed wherever possible.

intersectionWithPlane(p, n, atol=1e-05, sort='number')[source]

Return the intersection lines with plane (p,n).

Parameters:
  • p (coords_like (3,)) – A point in the cutting plane.

  • n (coords_like (3,)) – The positive normal on the plane

  • atol (float) – Tolerance value to consider points lying in the plane. A small positive value is recommended in order to include triangle edges that happen to fall exactly in the cutting plane.

  • sort ('number' | 'distance') – The sorting method for the connected components in the output Mesh. The default ‘number’ sorts in decreasing number of elements in the component. Setting to ‘distance’ will sort the parts according to increasing distance from the point p.

Returns:

Mesh – The intersection of the TriSurface with the plane. This is a Mesh of eltype ‘line’. The line segments in the Mesh are ordered in a way to form continuous lines. The Mesh has property numbers such that all segments forming a single continuous part have the same property value. The parts are assigned property numbers according to their sort order.

Notes

The splitProp() method can be used to get a list of separate Meshes.

slice(dir=0, nplanes=20)[source]

Intersect a surface with a series of parallel planes.

Parameters:
  • dir (int | array_like (3,)) – The direction of the normal on the planes. A single int (0..2) may be used to specify one of the global axes.

  • nplanes (int) – The number of planes to be used. The planes are spread at equal distances over the bbox of the surface.

Returns:

list of Mesh – A list of nplanes Meshes of type ‘line2’, being the intersections of the surface with each of the planes.

Notes

The intersections are obtained with intersectionWithPlane(). See there for more dretails on the returned Meshes.

refine(max_edges=None, min_cost=None, method='gts', log=False)[source]

Refine a TriSurface.

Refining a TriSurface means increasing the number of triangles and reducing their size, while keeping the changes to the modeled surface minimal. Construct a refined version of the surface. This uses the external program gtsrefine. The surface should be a closed orientable non-intersecting manifold. Use the check() method to find out.

Parameters:

  • max_edges: int: stop the refining process if the number of edges exceeds this value

  • min_cost: float: stop the refining process if the cost of refining an edge is smaller

  • log: boolean: log the evolution of the cost

  • verbose: boolean: print statistics about the surface

similarity(S)[source]

Compute the similarity with another TriSurface.

Compute a quantitative measure of the similarity of the volumes enclosed by two TriSurfaces. Both the calling and the passed TriSurface should be closed manifolds (see isClosedManifold()).

Returns a tuple (jaccard, dice, overlap). If A and B are two closed manifolds, VA and VB are their respective volumes, VC is the volume of the intersection of A and B, and VD is the volume of the union of A and B, then the following similarity measures are defined:

  • jaccard coefficient: VC / VD

  • dice: 2 * VC / (VA + VB)

  • overlap: VC / min(VA,VB)

Both jaccard and dice range from 0 when the surfaces are completely disjoint to 1 when the surfaces are identical. The overlap coefficient becomes 1 when one of the surfaces is completely inside the other.

This method uses gts library to compute the intersection or union. If that fails, nan values are returned.

fixNormals(method=None, *, outwards=True, return_parts=False, inplace=True)[source]

Fix the orientation of the normals.

Some surface operations may result in improperly oriented normals, switching directions from one triangle to the adjacent one. This method tries to reverse triangles with improperly oriented normals so that a singly oriented surface may be achieved.

Parameters:
  • method ('admesh' | 'internal') – The method to be used. If not specified, the default ‘internal’ is used and a warning is shown about the changed default. The ‘internal’ method does not rely on external software, and is relatively fast. As it does not fuse the nodes nor compacts the node array, it guarantees that the numbering of nodes and elements is retained. The ‘admesh’ uses an external program and needs to write the surface to a file and read it back. This method will always do a fuse and compaction, so if the surface was not fused and compacted before the call, the result may have different node and/or element numberings.

  • outwards (bool) – If True (default), a test is done whether the surface is a closed manifold, or a set of closed manifolds, and if so, the normals are oriented outwards. Setting this value to False may result in a closed surfaces with all normals pointing inside.

  • return_parts (bool) – If True, also returns an index identifying to which connected part each of the triangles belong. Part numbers are in order of decreasing number of triangles.

Raises:

ValueError – if the surface is not a manifold. Such a surface is not: orientable.

fixNormals_internal()[source]

Fix normals using an internal algorithm.

This is normally invoked as fixNormals('internal'). See fixNormals().

fixNormals_admesh()[source]

Fix normals using admesh.

This is normally invoked as fixNormals('admesh'). See fixNormals().

check(matched=True, verbose=False)[source]

Check the surface using gtscheck.

Uses the external program gtscheck to check whether the surface is an orientable, non self-intersecting manifold. This is a necessary condition for using the gts methods: split, coarsen, refine, boolean. Additionally, the surface should be closed: this can be checked with isClosedManifold().

Parameters:
  • matched (bool) – If True, self intersecting triangles are returned as element indices of self. This is the default. If False, the self intersecting triangles are returned as a separate TriSurface.

  • verbose (bool) – If True, prints the statistics reported by the gtscheck command.

Returns:

  • status (int) – Return code from the checking program. One of the following:

    • 0: the surface is an orientable, non self-intersecting manifold.

    • 1: the created GTS file is invalid: this should normally not occur.

    • 2: the surface is not an orientable manifold. This may be due to misoriented normals. The fixNormals() and reverse() methods may be used to help fixing the problem in such case.

    • 3: the surface is an orientable manifold but is self-intersecting. The self intersecting triangles are returned as the second return value.

  • intersect (None | list of ints | TriSurface) – None in case of a status 0, 1 or 2. For status value 3, returns the self intersecting triangles as a list of element numbers (if matched is True) or as a TriSurface (if matched is False).

split(base, verbose=False)[source]

Split the surface using gtssplit.

Splits the surface into connected and manifold components. This uses the external program gtssplit. The surface should be a closed orientable non-intersecting manifold. Use the check() method to find out.

This method creates a series of files with given base name, each file contains a single connected manifold.

coarsen(min_edges=None, max_cost=None, mid_vertex=False, length_cost=False, max_fold=1.0, volume_weight=0.5, boundary_weight=0.5, shape_weight=0.0, progressive=False, log=False, verbose=False)[source]

Coarsen a surface using gtscoarsen.

Construct a coarsened version of the surface. This uses the external program gtscoarsen. The surface should be a closed orientable non-intersecting manifold. Use the check() method to find out.

Parameters:
  • min_edges (int) – Stop the coarsening process if the number of edges was to fall below it.

  • max_cost (float) – Stop the coarsening process if the cost of collapsing an edge is larger than the specified value.

  • mid_vertex (bool) – Use midvertex as replacement vertex instead of the default, which is a volume optimized point.

  • length_cost (bool) – Use length^2 as cost function instead of the default optimized point cost.

  • max_fold (float) – Maximum fold angle in degrees.

  • volume_weight (float) – Weight used for volume optimization.

  • boundary_weight (float) – Weight used for boundary optimization.

  • shape_weight (float) – Weight used for shape optimization.

  • progressive (bool) – If True, write progressive surface file.

  • log (bool) – If Trye, log the evolution of the cost.

  • verbose (bool) – If True, print statistics about the surface.

gts_refine(max_edges=None, min_cost=None, log=False, verbose=False)[source]

Refine the TriSurface.

Refining a TriSurface means increasing the number of triangles and reducing their size, while keeping the changes to the modeled surface minimal. This uses the external program gtsrefine. The surface should be a closed orientable non-intersecting manifold. Use the check() method to find out.

Parameters:
  • max_edges (int) – Stop the refining process if the number of edges exceeds this value.

  • min_cost (float) – Stop the refining process if the cost of refining an edge is smaller. (Not recommended).

  • log (bool) – If True, log the evolution of the cost.

  • verbose (bool) – If True, print statistics about the surface.

Notes

If neither max_edges nor min_cost are specified, the refining process aims to double the number of edges.

gts_smooth(niter=1, lamb=0.5, verbose=False)[source]

Smooth the surface using gtssmooth.

Smooth a surface by applying iterations of a Laplacian filter. This uses the external program gtssmooth. The surface should be a closed orientable non-intersecting manifold. Use the check() method to find out.

Parameters:
  • lamb (float) – Laplacian filter parameter.

  • niter (int) – Number of iterations.

  • verbose (bool) – If True, print statistics about the surface.

gts_set(surf, op, prop=[1, 1, 2, 2], check=False, verbose=False)[source]

Perform a boolean operation with another surface.

Boolean operations between surfaces are a basic operation in free surface modeling. Both surfaces should be closed orientable non-intersecting manifolds. Use the check() method to find out.

Following is a list of defined operations, where surface 1 relates to self and surface 2 to the surf argument. For simplicity, the operations are identified by a short string. All returned surfaces are manifolds. The first four are the basic parts: these may be closed or not. The following operations are constructed by combining some of the basic results. These are mathematical set operation on the volumes inside the surfaces, and always result in closed surfaces.

Operation

Result

Computed from

i

the part of surface 1 inside surface 2

o

the part of surface 1 outside surface 2

2i

the part of surface 2 inside surface 1

2o

the part of surface 2 outside surface 1

+

the union of surfaces 1 and 2

o plus 2o

*

the intersection of surfaces 1 and 2

i plus 2i

-

the difference of surface 1 minus surface 2

o plus reversed 2i

2-

the difference of surface 2 minus surface 1

i plus reversed 2o

^

the symmetric difference of the surfaces

+ plus reversed *

Parameters:
  • surf (TriSurface) – Another TriSurface that is a closed manifold surface.

  • op (str or list of str) – The operation(s) to perform: one of the operations specified above, or a list of such operations. A special value a will return the full list of 9 surfaces in the above order.

  • prop (list of int) – A list of 4 integer values that will be set as props on the four base surfaces, to facilitate identification of the parts of the result(s). The default value will give prop values 1 or 2 depending on the original surface the parts belonged to. Specifying None or an empty list will return surfaces without props.

  • check (bool) – If True, a check is done that the surfaces are not self-intersecting; if one of them is, the set of self-intersecting faces is written (as a GtsSurface) on standard output

  • verbose (bool) – If True, print statistics about the surface.

Returns:

TriSurface or list thereof – A single manifold surface, or a list of such surfaces, corresponding to the specified oppetaion(s). The base operation may not be closed. The set operations always are closed.

Note

This method uses the external command ‘gtsset’ and will not run if it is not installed (available from pyformex/extras).

boolean(surf, op, check=False, verbose=False)[source]

Perform a boolean operation with another surface.

Boolean operations between surfaces are a basic operation in free surface modeling. Both surfaces should be closed orientable non-intersecting manifolds. Use the check() method to find out.

The boolean operations are set operations on the enclosed volumes: union(‘+’), difference(‘-’) or intersection(‘*’).

Parameters:
  • surf (TriSurface) – Another TriSurface that is a closed manifold surface.

  • op ('+', '-' or '*') – The boolean operation to perform: union(‘+’), difference(‘-‘) or intersection(‘*’).

  • check (bool) – If True, a check is done that the surfaces are not self-intersecting; if one of them is, the set of self-intersecting faces is written (as a GtsSurface) on standard output

  • verbose (bool) – If True, print statistics about the surface.

Returns:

TriSurface – A closed manifold TriSurface that is the volume union, difference or intersection of self with surf.

Note

This method uses the external command ‘gtsset’ and will not run if it is not installed (available from pyformex/extras).

intersection(surf, check=False, verbose=False)[source]

Return the intersection curve(s) of two surfaces.

Boolean operations between surfaces are a basic operation in free surface modeling. Both surfaces should be closed orientable non-intersecting manifolds. Use the check() method to find out.

Parameters:
  • surf (TriSurface) – A closed manifold surface.

  • check (bool, optional) – If True, a check is made that the surfaces are not self-intersecting; if one of them is, the set of self-intersecting faces is written (as a GtsSurface) on standard output

  • verbose (bool, optional) – If True, statistics about the surface are printed on stdout.

Returns:

Mesh – A Mesh with eltype Line2 holding all the line segments of the intersection curve(s).

inside(pts, method='gts', tol='auto', multi=True, keep=False)[source]

Test which of the points pts are inside the surface.

Parameters:
  • pts (:term_`coords_like`) – The points to check agains the surface.

  • method` (str) –

    Method to be used for the detection. Depending on the software you have installed the following are possible:

    • ’gts’: provided by pyformex-extra (default)

    • ’vtk’: provided by python-vtk (slower)

  • tol (float) – Tolerance on equality of floating point values.

  • multi (bool) – If True, uses multiprocessing to speed up the operation. Only used with method=’gts’.

  • keep (bool) – If True, the temporary directory with intermediate results is not erased. This may be useful for debugging purposes. Only used with method=’gts’.

Returns:

int array – The indices of the points that are inside the surface. The indices refer to the onedimensional list of points as obtained from Coords(pts).points().

outside(pts, **kargs)[source]

Returns the points outside the surface.

This is the complement of inside(). See there for parameters and return value.

voxelize(n, bbox=0.01, return_formex=False)[source]

Voxelize the volume inside a closed surface.

Parameters:
  • n (int or (int, int, int)) – Resolution, i.e. number of voxel cells to use along the three axes. If a single int is specified, the number of cells will be adapted according to the surface’s sizes() (as the voxel cells are always cubes). The specified number of voxels will be used along the largest direction.

  • bbox (float or (point,point)) – Defines the bounding box of the volume that needs to be voxelized. A float specifies a relative amount to add to the surface’s bounding box. Note that this defines the bounding box of the centers of the voxels.

  • return_formex (bool) – If True, also returns a Formex with the centers of the voxels.

Returns:

  • voxels (int array (nz,ny,nx)) – The array has a value 1 for the voxels whose center is inside the surface, else 0.

  • centers (Formex) – A plex-1 Formex with the centers of the voxels, and property values 0 or 1 if the point is respectively outside or inside the surface. The voxel cell ordering in the Formex is z-direction first, then y, then x.

Notes

See also example Voxelize, for saving the voxel values in a stack of binary images.

remesh(*, method='acvd', **kargs)[source]

Create a quality remesh of the TriSurface.

Remeshing a TriSurface means replacing the surface with a new mesh of triangles, which are more equally shaped, while trying to keep the represented surface as close as possible to the original.

Parameters:
  • method (str) –

    One of ‘acvd’ or ‘instant’. The first character suffices. Depending on this value, one of the remesh_acvd(), remesh_instant() is called.

    The ‘acvd’ method is included with pyFormex and is normally always available on a successful install. The ‘instant’ method requires an external program ‘instant-meshes’. The Help menu contains an option to install it.

  • kargs – Keyword arguments to be passed to the specific method selected. See the specific method for explanation of the parameters.

Returns:

TriSurface | Mesh | None – In most cases a TriSurface is returned. The ‘instant’ method however allows remeshing to quads. In that cases a Mesh of eltype ‘quad4’ is returner. If the external conversion failed, None is returned.

Raises:

ValueError: – If the requested external remeshing program is not available.

See also

lib.clust.remesh_acvd()

remesh using the ACVD technique

remesh_instant

remesh using the external program ‘instant-meshes’

tetgen(quality=2.0, volume=None, filename=None)[source]

Create a tetrahedral mesh inside the surface.

This uses tetMesh() to generate a quality tetrahedral mesh inside the surface. The surface should be a closed manifold.

Parameters:
  • quality (float) – The quality of the output tetrahedral mesh. The value is a constraint on the circumradius-to-shortest-edge ratio. The default (2.0) already provides a high quality mesh. Providing a larger value will reduce quality but increase speed. With quality=None, no quality constraint will be imposed.

  • volume (float, optional) – If provided, applies a maximum tetrahedron volume constraint.

  • filename (path_like) – Specifies where the intermediate files will be stored. The default will use a temporary directory which will be destroyed after return. If the path of an existing directory is provided, the files will be stored in that directory with a name ‘surface.off’ for the original surface model and files ‘surface.1.*’ for the generated tetrahedral model (in tetgen format). If the path does not exist or is an existing file, the parent directory should exist and files are stored with the given file name as base. Existing files will be silently overwritten.

Returns:

Mesh – A tetrahedral Mesh (eltype=’tet4’) filling the input surface, provided the tetMesh() function finished successfully.

surface2webgl(name, caption=None)

Create a WebGL model of a surface

  • S: TriSurface

  • name: basename of the output files

  • caption: text to use as caption

webgl(name, caption=None)

Create a WebGL model of a surface

  • S: TriSurface

  • name: basename of the output files

  • caption: text to use as caption

pzf_dict()[source]

Construct common part of all Geometry pzf dicts

44.2. Functions defined in module trisurface

trisurface.fillBorder(border, method='radial', dir=None)[source]

Create a triangulated surface inside a given closed polygonal line.

Parameters:
  • border (PolyLine, Mesh or Coords) –

    A closed polygonal line that forms the border of the triangulated surface to be created. The polygon does not have to be planar. The line can be provided as one of the following:

    • a closed PolyLine,

    • a 2-plex Mesh, with a Connectivity table such that the elements in the specified order form a closed polyline,

    • a simple Coords holding the subsequent vertices of the polygonal border line.

  • method (str) –

    Specifies the algorithm to be used to fill the polygon. Currently available are:

    • ’radial’: this method adds a central point and connects all border segments with the center to create triangles.

    • ’border’: this method creates subsequent triangles by connecting the endpoints of two consecutive border segments and thus works its way inwards until the hole is closed. Triangles are created at the line segments that form the smallest angle.

    • ’planar’: this method projects the border on a plane, fills the border in 2D, then maps that back to the original border. The projection direction can be specified with dir.

    See also Notes below.

  • dir ((3,) array_like, optional) – A vector specyfing the direction of the projection in the case of method='planar'. If not provided, the best direction is automatically choosen.

Returns:

TriSurface – A TriSurface filling the hole inside the border.

Notes

The ‘radial’ method produces nice results if the border is relative smooth, nearly convex and nearly planar. It adds an extra point though, which may be unwanted. On irregular 3D borders there is a high change that the resulting TriSurface contains intersecting triangles.

The ‘border’ method is slower on large borders, does not introduce any new point and has a better chance of avoiding intersecting triangles on irregular 3D borders.

The ‘planar’ method gives very good results if the border curve is more or less planar.

The resulting surface can be checked for intersecting triangles with the check() method.

trisurface.instant_meshes(infile, outfile=None, **kargs)[source]

Remesh a tri3 mesh to a quality tri3 and/or quad4 mesh

Uses the external ‘Instant Meshes’ program to remesh a tri3 mesh to a tri3 and/or quad4 mesh of the desired quality.

Parameters:
  • infile (path_like) – An .obj file containing a pure tri3 mesh.

  • outfile (path_like) – The output file with the quad (or quad dominated) Mesh. It can be a .obj or .ply file. If not provided, it is generated from the input file with the ‘.obj’ suffix replaced ‘with _quad.obj’.

  • threads (int) – Number of threads to use in parallel computations.

  • deterministic (bool) – If True, prefer (slower) deterministic algorithms. Default False.

  • crease (float) – Dihedral angle threshold for creases.

  • smooth (int) – Number of smoothing & ray tracing reprojection steps (default: 2). Setting this to 0 may result in degenerate quads (with two adjacent edges along the same line).

  • dominant (bool) – If True, generate a quad dominant mesh instead of a pure quad mesh. The output may contain some triangles and pentagones as well. Default False.

  • intrinsic (bool) – If True, use intrinsic mode (extrinsic is the default).

  • boundaries (bool) – If True, align the result on the boundaries. Default False. Only applies when the surface is not closed.

  • posy (3 | 4 | 6) – Specifies the position symmetry type. Default 4.

  • rosy (2 | 4 | 6) – Specifies the orientation symmetry type. Default 4.

  • scale (float) – The intended edge length of the quad elements. Ignored if either faces or vertices is provided. See notes.

  • faces (int) – The intended number of quads in the output mesh. Ignored if vertices is provided. See notes.

  • vertices (int) – The intended number of vertices in the output mesh. See notes.

Returns:

Path | None – The path of the output file if the conversion was successful, else None.

Notes

The ‘Instant Meshes’ executable should be installed as ‘instant-meshes’.

To control the output resolution, one should specify exactly one of scale, faces or vertices. These are mutually exclusive.

If a pure quad mesh is requested (the default), the number of faces and vertices is likely to end up being around 4 times larger and the edges two times shorter than requested. This is because the initial remeshing may end up with some triangles and/or pentagons, which then require a subdivision of all faces into smaller quads. You may anticipate to this by specifying smaller values. This late subdivision is not done if dominant=True is specified, or if the initial remesh does not have any triangles or pentagons.

With dominant=False, posy = 3 or 6 results in a Tri3 Mesh, while posy = 4 yields a Quad4 Mesh. The best quality is usually obtained with posy=rosy=6 to produce triangles and posy=rosy=4 for quads.

See also

TriSurface.remesh()

apply remeshing on a TriSurface

trisurface.remesh_instant(S, *, infile=None, outfile=None, nplex=None, **kargs)[source]

Create a quality remesh of the TriSurface.

Uses instant_meshes() to remesh a TriSurface into a quality Tri3 or Quad4 Mesh.

Parameters:
  • S (TriSurface) – The TriSurface to be remeshed.

  • infile (path_like) – The name of an .obj file where the TriSurface will be stored for processing. If not provided, a temporary file is used.

  • outfile (path_like) – The name of an .obj file for storing the output Mesh. If not provided, it is generated from the infile with the ‘.obj’ suffix replaced ‘with _remesh.obj’.

  • nplex (3 | 4) – This is a convenient parameter to quickly create a quality mesh of triangles or quads. It overwrites the parameters rosy and posy with values 6 for nplex=3 and 4 for nplex=4.

  • kargs – Other keyword arguments passed to instant_meshes(). All the keyword parameters accepted by that function, except for ‘dominant, can be specified here.

Returns:

Mesh | None – A Mesh of eltype ‘tri3’ or ‘quad4’ if the conversion was successful, or else None.

Notes

If neither scale, faces or vertices is provided, vertices will be set equal to the number of vertices in the TriSurface. This is because the default of instant_meshes() results in a much too coarse Mesh.

If the boundaries parameter is not provided, it is set True if the TriSurface is not a closed manifold.

As a side effect, if file names were specified, the .obj files with the original TriSurface and remeshed surface remain available.