8. 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.

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

A class representing a triangulated 3D surface.

The surface contains ntri triangles, each having 3 vertices with 3 coordinates. The surface can be initialized from one of the following:

  • a (ntri,3,3) shaped array of floats
  • a Formex with plexitude 3
  • a Mesh with plexitude 3
  • an (ncoords,3) float array of vertex coordinates and an (ntri,3) integer array of vertex numbers
  • an (ncoords,3) float array of vertex coordinates, an (nedges,2) integer array of vertex numbers, an (ntri,3) integer array of edges numbers.

Additionally, a keyword argument prop= may be specified to set property values.

nedges()[source]

Return the number of edges of the TriSurface.

nfaces()[source]

Return the number of faces of the TriSurface.

vertices()[source]

Return the coordinates of the nodes of the TriSurface.

shape()[source]

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

getElemEdges()[source]

Get the faces’ edge numbers.

setCoords(coords)[source]

Change the coords.

setElems(elems)[source]

Change the elems.

setEdgesAndFaces(edges, faces)[source]

Change the edges and faces.

append(S)[source]

Merge another surface with self.

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)[source]

Read a surface from file.

If no file type is specified, it is derived from the filename extension. Currently supported file types:

  • .off
  • .gts
  • .stl (ASCII or BINARY)
  • .neu (Gambit Neutral)
  • .smesh (Tetgen)

Compressed (gzip or bzip2) files are also supported. Their names should be the normal filename with ‘.gz’ or ‘.bz2’ appended. These files are uncompressed on the fly during the reading and the uncompressed versions are deleted after reading.

The file type can be specified explicitely to handle file names where the extension does not directly specify the file type.

write(fname, ftype=None, color=None)[source]

Write the surface to file.

If no filetype is given, it is deduced from the filename extension. If the filename has no extension, the ‘off’ file type is used. For a file with extension ‘stl’, the ftype may be ‘stla’ or ‘stlb’ to force ascii or binary STL format. The color is only useful for ‘stlb’ format.

avgVertexNormals()[source]

Compute the average normals at the vertices.

areaNormals()[source]

Compute the area and normal vectors of the surface triangles.

The normal vectors are normalized. The area is always positive.

The values are returned and saved in the object.

areas()[source]

Return the areas of all facets

volume()[source]

Return the enclosed volume of the surface.

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

volumeInertia(density=1.0)[source]

Return the inertia properties of the enclosed volume of the surface.

The surface should be a closed manifold and is supposed to be the border of a volume of constant density 1.

Returns an inertia.Inertia instance with attributes

  • mass: the total mass (float)
  • ctr: the center of mass: float (3,)
  • tensor: the inertia tensor in the central axes: shape (3,3)

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

See inertia() for the inertia of the surface.

Example:

>>> from pyformex.simple import sphere
>>> S = sphere(8)
>>> I = S.volumeInertia()
>>> print(I.mass)  # doctest: +ELLIPSIS
4.1526...
>>> print(I.ctr)
[ 0.  0.  0.]
>>> print(I.tensor)
[[ 1.65  0.   -0.  ]
 [ 0.    1.65 -0.  ]
 [-0.   -0.    1.65]]
curvature(neighbours=1)[source]

Return the curvature parameters at the nodes.

This uses the nodes that are connected to the node via a shortest path of ‘neighbours’ edges. Eight values are returned: the Gaussian and mean curvature, the shape index, the curvedness, the principal curvatures and the principal directions.

inertia(volume=False, density=1.0)[source]

Return inertia related quantities of the surface.

This computes the inertia properties of the centroids of the triangles, using the triangle area as a weight. The result is therefore different from self.coords.inertia() and usually better suited for the surface, especially if the triangle areas differ a lot.

Returns a tuple with the center of gravity, the principal axes of inertia, the principal moments of inertia and the inertia tensor.

See also volumeInertia().

surfaceType()[source]

Check whether the TriSurface is a manifold and if it’s closed.

borderEdges()[source]

Detect the border elements of TriSurface.

The border elements are the edges having less than 2 connected elements. Returns True where edge is on the border.

borderEdgeNrs()[source]

Returns the numbers of the border edges.

borderNodeNrs()[source]

Detect the border nodes of TriSurface.

The border nodes are the vertices belonging to the border edges. Returns a list of vertex numbers.

isManifold()[source]

Check whether the TriSurface is a manifold.

A surface is a manifold if a small sphere exists that cuts the surface to a surface that can continously be deformed to an open disk.

nonManifoldEdges()[source]

Return the non-manifold edges.

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

Returns the indices of the non-manifold edges in a TriSurface.

nonManifoldEdgesFaces()[source]

Return the non-manifold edges and faces.

Returns a tuple of:

  • the list of edges that connect 3 or more faces,
  • the list of faces connected to any of these edges.
isClosedManifold()[source]

Check whether the TriSurface is a closed manifold.

isConvexManifold()[source]

Check whether the TriSurface is a convex manifold.

removeNonManifold()[source]

Remove the non-manifold edges.

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

Returns the reduced surface.

checkBorder()[source]

Return the border of TriSurface.

Returns a list of connectivity tables. Each table holds the subsequent line segments of one continuous contour of the border of the surface.

border(compact=True)[source]

Return the border(s) of TriSurface.

The complete border of the surface is returned as a list of plex-2 Meshes. Each Mesh constitutes a continuous part of the border. By default, the Meshes are compacted. Setting compact=False will return all Meshes with the full surface coordinate sets. This is usefull for filling the border and adding to the surface.

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

Fill the border areas of a surface to make it closed.

Returns a list of surfaces, each of which fills a singly connected part of the border of the input surface. Adding these surfaces to the original will create a closed surface. The surfaces will have property values set above those used in the parent surface. If the surface is already closed, an empty list is returned.

There are three methods: ‘radial’, ‘planar’ and ‘border’, corresponding to the methods of the fillBorder() function.

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

This method needs documentation!!!!

edgeCosAngles(return_mask=False)[source]

Return the cos of the angles over all edges.

The surface should be a manifold (max. 2 elements per edge). Edges adjacent to only one element get cosangles = 1.0. If return_mask == True, a second return value is a boolean array with the edges that connect two faces.

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

edgeAngles()[source]

Return the angles over all edges (in degrees). It is the angle (0 to 180) between 2 face normals.

edgeSignedAngles(return_mask=False)[source]

Return the signed angles over all edges (in degrees). It is the angle (-180 to 180) between 2 face normals.

Positive/negative angles are associated to convexity/concavity at that edge. The border edges attached to one triangle have angle 0. NB: The sign of the angle is relevant if the surface has fixed normals. Should this check be done?

edgeLengths()[source]

Returns the lengths of all edges

Returns an array with the length of all the edges in the surface. As a side effect, this stores the connectivities of the edges to nodes and the elements to edges in the attributes edges, resp. elem_edges.

perimeters()[source]

Compute the perimeters of all triangles.

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 relative to this same ratio for an equilateral triangle with the same area. The quality is then one for an equilateral triangle and tends to zero for a very stretched triangle.

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 edge ratio (2 over square root 3).

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.

distanceOfPoints(X, return_points=False)[source]

Find the distances of points X to the TriSurface.

The distance of a point is either: - the closest perpendicular distance to the facets; - the closest perpendicular distance to the edges; - the closest distance to the vertices.

X is a (nX,3) shaped array of points. If return_points = True, a second value is returned: an array with the closest (foot)points matching X.

degenerate()[source]

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

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

Returns the list of degenerate element numbers in a sorted array.

removeDegenerate(compact=False)[source]

Remove the degenerate elements from a TriSurface.

Returns a TriSurface with all degenerate elements removed. By default, the coords set is unaltered and will still contain all points, even ones that are no longer connected to any element. To reduce the coordinate set, set the compact argument to True or use the compact() method afterwards.

collapseEdge(edg)[source]

Collapse an edge in a TriSurface.

Collapsing an edge removes all the triangles connected to the edge and replaces the two vertices by a single one, placed at the center of the edge. Triangles only having one of the edge vertices, will all be connected to the new vertex.

Parameters:

  • edg: the index of the edg to be removed. This is an index in the array of edges as returned by getElemEdges().

Returns a TriSurface with the specified edge number removed.

offset(distance=1.0)[source]

Offset a surface with a certain distance.

All the nodes of the surface are translated over a specified distance along their normal vector.

dualMesh(method='median')[source]

Return the dual mesh of a compacted triangulated surface.

It creates a new triangular mesh where all triangles with prop p represent the dual mesh region around the original surface node p. For more info, see http://users.led-inc.eu/~phk/mesh-dualmesh.html.

  • method: ‘median’ or ‘voronoi’.

Returns:

  • method = ‘median’: the Median dual mesh and the area of the region around each node. The sum of the node-based areas is equal to the original surface area.
  • method = ‘voronoi’: the Voronoi polyeders and a None.
featureEdges(angle=60.0)[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 angle. The non feature edges then represent edges on a rather smooth surface.

Parameters:

  • angle: The angle by which the normals on adjacent triangles should differ in order for the edge to be marked as a feature.

Returns a boolean array with shape (nedg,) where the feature angles are marked with True.

Note

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])
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 reach without ever crossing a sharp edge angle. More precisely, any two elements that can be connected by a line not crossing an edge between two elements having their normals differ more than angle (in degrees), will belong to the same part.

The partitioning is returned as an integer array specifying the part number for eacht triangle.

By default the parts are assigned property numbers in decreasing order of the number of triangles in the part. Setting the sort argument to ‘area’ will sort the parts according to decreasing area. Any other value will return the parts unsorted.

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.

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

Parameters:

  • p: float, shape (3,): a point in the cutting plane
  • n: float, shape (3,): the normal vector to the plane
  • side: ‘’, ‘+’ or ‘-‘: selector of 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:

A tuple of two TriSurfaces, or a single TriSurface, depending on the value of side. The returned surfaces will have their normals fixed wherever possible. Property values will be set containing the triangle number of the original surface from which the elements resulted.

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

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

Cuts the surface with one or more plane and returns either one side or both.

Parameters:

  • p,`n`: a point and normal vector defining the cutting plane. p and n can be sequences of points and vector, allowing to cut with multiple planes. Both p and n have shape (3) or (npoints,3).

The parameters are the same as in Formex.CutWithPlane(). The returned surface will have its normals fixed wherever possible.

intersectionWithPlane(p, n, atol=0.0, sort='number')[source]

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

Returns a plex-2 mesh with the line segments obtained by cutting all triangles of the surface with the plane (p,n) p is a point specified by 3 coordinates. n is the normal vector to a plane, specified by 3 components.

The return value is a plex-2 Mesh where the line segments defining the intersection are sorted to form continuous lines. The Mesh has property numbers such that all segments forming a single continuous part have the same property value.

By default the parts are assigned property numbers in decreasing order of the number of line segments in the part. Setting the sort argument to ‘distance’ will sort the parts according to increasing distance from the point p.

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

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

Intersect a surface with a sequence of planes.

A sequence of nplanes planes with normal dir is constructed at equal distances spread over the bbox of the surface.

The return value is a list of intersectionWithPlane() return values, i.e. a list of Meshes, one for every cutting plane. In each Mesh the simply connected parts are identified by property number.

smooth(method='lowpass', iterations=1, lambda_value=0.5, neighbourhood=1, alpha=0.0, beta=0.2)[source]

Smooth the surface.

Returns a TriSurface which is a smoothed version of the original. Two smoothing methods are available: ‘lowpass’ and ‘laplace’.

Parameters:

  • method: ‘lowpass’ or ‘laplace’
  • iterations: int: number of iterations
  • lambda_value: float: lambda value used in the filters

Extra parameters for ‘lowpass’ and ‘laplace’:

  • neighbourhood: int: maximum number of edges followed in defining the node neighbourhood

Extra parameters for ‘laplace’:

  • alpha, beta: float: parameters for the laplace method.

Returns the smoothed TriSurface

smoothLowPass(iterations=2, lambda_value=0.5, neighbours=1)[source]

Apply a low pass smoothing to the surface.

smoothLaplaceHC(iterations=2, lambda_value=0.5, alpha=0.0, beta=0.2)[source]

Apply Laplace smoothing with shrinkage compensation to the surface.

refine(max_edges=None, min_cost=None, method='gts')[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. 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 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(outwards=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 improperly oriented normals so that a singly oriented surface is achieved.

If the surface is a (possibly non-orientable) manifold, the result will be an orientable manifold.

If the surface is a closed manifold, the normals will be oriented to the outside. This is done by computing the volume inside the surface and reversing the normals if that turns out to be negative.

Parameters:

  • outwards: boolean: if True (default), a test is done whether the surface is a closed manifold, and if so, the normals are oriented outwards. Setting this value to False will skip this test and the (possible) reversal of the normals.
check(matched=True, verbose=False)[source]

Check the surface using gtscheck.

Uses 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, wich can be checked with isClosedManifold()).

Returns a tuple of:

  • an integer return code with the value:
    • 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.
  • the intersecting triangles in the case of a return code 3, else None. If matched==True, intersecting triangles are returned as element indices of self, otherwise as a separate TriSurface object.

If verbose is True, prints the statistics reported by the gtscheck command.

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 the 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: stops the coarsening process if the number of edges was to fall below it
  • max_cost: float: stops the coarsening process if the cost of collapsing an edge is larger
  • mid_vertex: boolean: use midvertex as replacement vertex instead of the default, which is a volume optimized point
  • length_cost: boolean: 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: boolean: write progressive surface file
  • log: boolean: log the evolution of the cost
  • verbose: boolean: 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. 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
gts_smooth(iterations=1, lambda_value=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:

  • lambda_value: float: Laplacian filter parameter
  • iterations: int: number of iterations
  • verbose: boolean: print statistics about the surface

See also: smoothLowPass(), smoothLaplaceHC()

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

Test which of the points pts are inside the surface.

Parameters:

  • pts: a Coords or compatible.
  • method: string: method to be used for the detection. Depending on the software you have installed the following are possible:
    • ‘gts’: provided by pyformex-extra
    • ‘vtk’: provided by python-vtk (slower)
  • tol: tolerance on equality of floating point values

Returns an integer array with the indices of the points that are inside the surface. The indices refer to the onedimensional list of points as obtained from pts.points().

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 use 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 an int array of shape (nz,ny,nx) with value 1 for the voxels whose center is inside the surface, else 0. If return_formex is True, also returns 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.

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

tetgen(quality=True, volume=None, filename=None, format='.off')[source]

Create a tetrahedral mesh inside the surface

  • quality: if True, the output will be a quality mesh The circumradius-to-shortest-edge ratio can be constrained by specifying a float value for quality (default is 2.0) - volume: float: applies a maximum tetrahedron volume constraint
  • filename: if specified, the surface model will be saved on this file and the tetgen models will be named likewise. If unspecified, temporary file names will be used.

If the creation of the tetrahedral model is succesful, the resulting tetrahedral mesh is returned.

boolean(surf, op, check=False, verbose=False)

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: a closed manifold surface
  • op: boolean operation: one of ‘+’, ‘-‘ or ‘*’.
  • filt: a filter command to be executed on the gtsset output
  • ext: extension of the result file
  • check: boolean: check 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: boolean: print statistics about the surface

Returns: a closed manifold TriSurface

gtsset(surf, op, filt='', ext='.tmp', curve=False, check=False, verbose=False)

_Perform the boolean/intersection methods.

See the boolean/intersection methods for more info. Parameters not explained there:

  • curve: if True, an intersection curve is computed, else the surface.

Returns the resulting TriSurface (curve=False), or a plex-2 Formex (curve=True), or None if the input surfaces do not intersect.

intersection(surf, check=False, verbose=False)

Return the intersection curve 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: a closed manifold surface
  • check: boolean: check 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: boolean: print statistics about the surface

Returns: a list of intersection curves.

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

8.1. Functions defined in module trisurface

trisurface.adjacencyArrays(elems, nsteps=1)[source]

Create adjacency arrays for 2-node elements.

elems is a (nr,2) shaped integer array. The result is a list of adjacency arrays, where row i of adjacency array j holds a sorted list of the nodes that are connected to node i via a shortest path of j elements, padded with -1 values to create an equal list length for all nodes. This is: [adj0, adj1, …, adjj, … , adjn] with n=nsteps.

Examples

>>> for a in adjacencyArrays([[0,1],[1,2],[2,3],[3,4],[4,0]],3):
...     print(a)
[[0]
 [1]
 [2]
 [3]
 [4]]
[[1 4]
 [0 2]
 [1 3]
 [2 4]
 [0 3]]
[[2 3]
 [3 4]
 [0 4]
 [0 1]
 [1 2]]
[]
trisurface.stlConvert(stlname, outname=None, binary=False, options='-d')[source]

Transform an .stl file to .off or .gts or binary .stl format.

Parameters:

  • stlname: name of an existing .stl file (either ascii or binary).
  • outname: name of the output file. The extension defines the format and should be one of ‘.off’, ‘.gts’, ‘.stl’, ‘.stla’, or .stlb’. As a convenience, if a file extension only is given (other than ‘.stl’), then the outname will be constructed by changing the extension of the input stlname.
  • binary: if the extension of outname is ‘.stl’, defines whether the output format is a binary or ascii STL format.

If the outname file exists and its mtime is more recent than the stlname, the outname file is considered uptodate and the conversion program will not be run.

The conversion program will be choosen depending on the extension. This uses the external commands ‘admesh’ or ‘stl2gts’.

The return value is a tuple of the output file name, the conversion program exit code (0 if succesful) and the stdout of the conversion program (or a ‘file is already uptodate’ message).

trisurface.read_stl(fn, intermediate=None)[source]

Read a surface from .stl file.

This is done by first coverting the .stl to .gts or .off format. The name of the intermediate file may be specified. If not, it will be generated by changing the extension of fn to ‘.gts’ or ‘.off’ depending on the setting of the ‘surface/stlread’ config setting.

Return a coords,edges,faces or a coords,elems tuple, depending on the intermediate format.

trisurface.curvature(coords, elems, edges, neighbours=1)[source]

Calculate curvature parameters at the nodes.

Algorithms based on Dong and Wang 2005; Koenderink and Van Doorn 1992. This uses the nodes that are connected to the node via a shortest path of ‘neighbours’ edges. Eight values are returned: the Gaussian and mean curvature, the shape index, the curvedness, the principal curvatures and the principal directions.

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

Create a surface inside a given closed border line.

The border line is a closed polygonal line and can be specified as one of the following:

  • a closed PolyLine,
  • a 2-plex Mesh, with a Connectivity table such that the elements in order form a closed polyline,
  • a simple Coords specifying the subsequent vertices of the polygonal border line.

The return value is a TriSurface filling the hole inside the border.

There are currently two fill methods available:

  • ‘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.

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 result contains intersecting triangles.

This ‘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 resulting surface can be checked for intersecting triangles by the check() method.

Note

Because the ‘border’ does not create any new points, the returned surface will use the same point coordinate array as the input object.

trisurface.find_row(mat, row, nmatch=None)[source]

Find all rows in matrix matching given row.

trisurface.find_nodes(nodes, coords)[source]

Find nodes with given coordinates in a node set.

nodes is a (nnodes,3) float array of coordinates. coords is a (npts,3) float array of coordinates.

Returns a (n,) integer array with ALL the node numbers matching EXACTLY ALL the coordinates of ANY of the given points.

trisurface.find_first_nodes(nodes, coords)[source]

Find nodes with given coordinates in a node set.

nodes is a (nnodes,3) float array of coordinates. coords is a (npts,3) float array of coordinates.

Returns a (n,) integer array with THE FIRST node number matching EXACTLY ALL the coordinates of EACH of the given points.

trisurface.find_triangles(elems, triangles)[source]

Find triangles with given node numbers in a surface mesh.

elems is a (nelems,3) integer array of triangles. triangles is a (ntri,3) integer array of triangles to find.

Returns a (ntri,) integer array with the triangles numbers.

trisurface.remove_triangles(elems, remove)[source]

Remove triangles from a surface mesh.

elems is a (nelems,3) integer array of triangles. remove is a (nremove,3) integer array of triangles to remove.

Returns a (nelems-nremove,3) integer array with the triangles of nelems where the triangles of remove have been removed.