# Local Mesh Cleanup¶

Meshes coming from the real world are rarely clean. Artifacts such as degeneracies, duplicate vertex/triangles and self-intersections are rampant (See the about page in our Thingi10K dataset). Unfortunately, many geometry processing operations have strict and often unspecified requirements on the cleanness of the input geometry. Here, we provide a number of handy routines to facilitate the task of cleaning up a mesh.

## Remove isolated vertices¶

Isolated vertices are vertices not referred by any face or voxel. They often does not contribute to the geometry (except for the case of point cloud), and thus can be safely removed.

pymesh.remove_isolated_vertices(mesh)

Wrapper function of remove_isolated_vertices_raw().

Parameters: mesh (Mesh) – Input mesh. 2 values are returned. output_mesh (Mesh): Output mesh. infomation (dict): A dict of additional informations. The following fields are defined in infomation: num_vertex_removed: Number of vertex removed. ori_vertex_index: Original vertex index. That is vertex i of output_vertices has index ori_vertex_index[i] in the input vertex array.
pymesh.remove_isolated_vertices_raw(vertices, elements)

Remove isolated vertices.

Parameters: vertices (numpy.ndarray) – Vertex array with one vertex per row. elements (numpy.ndarray) – Element array with one face per row. 3 values are returned. output_vertices: Output vertex array with one vertex per row. output_elements: Output element array with one element per row. infomation: A dict of additional informations. The following fields are defined in infomation: num_vertex_removed: Number of vertex removed. ori_vertex_index: Original vertex index. That is vertex i of output_vertices has index ori_vertex_index[i] in the input vertex array.

## Remove duplicate vertices¶

Duplicate or near duplicate vertices are vertices with nearly same coordinates. Two vertices can be considered as duplicates of each other if their Euclidean distance is less than a tolerance (labeled tol). Duplicate vertices can often be merged into a single vertex.

pymesh.remove_duplicated_vertices(mesh, tol=1e-12, importance=None)

Wrapper function of remove_duplicated_vertices_raw().

Parameters: mesh (Mesh) – Input mesh. tol (float) – (optional) Vertices with distance less than tol are considered as duplicates. Default is 1e-12. importance (numpy.ndarray) – (optional) Per-vertex importance value. When discarding duplicates, the vertex with the highest importance value will be kept. 2 values are returned. output_mesh (Mesh): Output mesh. information (dict): A dict of additional informations. The following fields are defined in information: num_vertex_merged: number of vertex merged. index_map: An array that maps input vertex index to output vertex index. I.e. vertex i will be mapped to index_map[i] in the output.
pymesh.remove_duplicated_vertices_raw(vertices, elements, tol=1e-12, importance=None)

Merge duplicated vertices into a single vertex.

Parameters: vertices (numpy.ndarray) – Vertices in row major. elements (numpy.ndarray) – Elements in row major. tol (float) – (optional) Vertices with distance less than tol are considered as duplicates. Default is 1e-12. importance (numpy.ndarray) – (optional) Per-vertex importance value. When discarding duplicates, the vertex with the highest importance value will be kept. 3 values are returned. output_vertices: Output vertices in row major. output_elements: Output elements in row major. information: A dict of additional informations. The following fields are defined in information: num_vertex_merged: number of vertex merged. index_map: An array that maps input vertex index to output vertex index. I.e. vertex i will be mapped to index_map[i] in the output.

## Collapse short edges¶

Short edges are edges with length less than a user specified threshold. Use the following functions to collapse all short edges in the mesh. The output mesh guarantees to have no short edges.

pymesh.collapse_short_edges(mesh, abs_threshold=0.0, rel_threshold=None, preserve_feature=False)

Wrapper function of collapse_short_edges_raw().

Parameters: mesh (Mesh) – Input mesh. abs_threshold (float) – (optional) All edge with length below or equal to this threshold will be collapsed. This value is ignored if rel_thresold is not None. rel_threashold (float) – (optional) Relative edge length threshold based on average edge length. e.g. rel_threshold=0.1 means all edges with length less than 0.1 * ave_edge_length will be collapsed. preserve_feature (bool) – True if shape features should be preserved. Default is false. 2 values are returned. output_Mesh (Mesh): Output mesh. information (dict): A dict of additional informations. The following attribute are defined: face_sources: The index of input source face of each output face. The following fields are defined in information: num_edge_collapsed: Number of edge collapsed.
pymesh.collapse_short_edges_raw(vertices, faces, abs_threshold=0.0, rel_threshold=None, preserve_feature=False)

Convenient function for collapsing short edges.

Parameters: vertices (numpy.ndarray) – Vertex array. One vertex per row. faces (numpy.ndarray) – Face array. One face per row. abs_threshold (float) – (optional) All edge with length below or equal to this threshold will be collapsed. This value is ignored if rel_thresold is not None. rel_threashold (float) – (optional) Relative edge length threshold based on average edge length. e.g. rel_threshold=0.1 means all edges with length less than 0.1 * ave_edge_length will be collapsed. preserve_feature (bool) – True if shape features should be preserved. Default is false. 3 values are returned. output_vertices: Output vertex array. One vertex per row. output_faces: Output face array. One face per row. information: A dict of additional informations. The following fields are defined in information: num_edge_collapsed: Number of edge collapsed. source_face_index: An array tracks the source of each output face. That is face i of the output_faces comes from face source_face_index[i] of the input faces.

## Split long edges¶

Long edges are sometimes undesirable as well. Use the following functions to split long edges into 2 or more shorter edges. The output mesh guarantees to have no edges longer than the user specified threshold.

pymesh.split_long_edges(mesh, max_edge_length)

Wrapper function of split_long_edges_raw().

Parameters: mesh (Mesh) – Input mesh. max_edge_length (float) – Maximum edge length allowed. All edges longer than this will be split. 2 values are returned. output_mesh (Mesh): Output mesh. information: A dummy dict that is currently empty. It is here to ensure consistent interface across the module.
pymesh.split_long_edges_raw(vertices, faces, max_edge_length)

Split long edges.

Parameters: vertices (numpy.ndarray) – Vertex array with one vertex per row. faces (numpy.ndarray) – Face array with one face per row. max_edge_length (float) – Maximum edge length allowed. All edges longer than this will be split. 3 values are returned. output_vertices: Output vertex array with one vertex per row. output_faces: Output face array with one face per row. information: A dummy dict that is currently empty. It is here to ensure consistent interface across the module.

## Remove duplicate faces¶

Duplicate faces are faces consisting of the same vertices. They are often not desirable and may cause numerical problems. Use the following functions to remove them.

pymesh.remove_duplicated_faces(mesh, fins_only=False)

Wrapper function of remove_duplicated_faces_raw().

Parameters: mesh (Mesh) – Input mesh. fins_only (bool) – If set, only remove fins. 2 values are returned. output_mesh (Mesh): Output mesh. information (dict): A dict of additional informations. The following fields are defined in information: ori_face_index: An array of original face indices. I.e. face i of the output_faces has index ori_face_index[i] in the input vertices.
pymesh.remove_duplicated_faces_raw(vertices, faces, fins_only=False)

Remove duplicated faces.

Duplicated faces are defined as faces consist of the same set of vertices. Depending on the face orientation. A special case of duplicated faces is a fin. A fin is defined as two duplicated faces with opposite orientaiton.

If fins_only is set to True, all fins in the mesh are removed. The output mesh could still contain duplicated faces but no fins.

If fins_only is not True, all duplicated faces will be removed. There could be two caes:

If there is a dominant orientation, that is more than half of the faces are consistently orientated, and fins_only is False, one face with the dominant orientation will be kept while all other faces are removed.

If there is no dominant orientation, i.e. half of the face are positively orientated and the other half is negatively orientated, all faces are discarded.

Parameters: vertices (numpy.ndarray) – Vertex array with one vertex per row. faces (numpy.ndarray) – Face array with one face per row. fins_only (bool) – If set, only remove fins. 3 values are returned. output_vertices: Output vertex array, one vertex per row. output_faces: Output face array, one face per row. information: A dict of additional informations. The following fields are defined in information: ori_face_index: An array of original face indices. I.e. face i of the output_faces has index ori_face_index[i] in the input vertices.

## Remove obtuse triangles¶

Obtuse triangles are often not desirable due to their geometric nature (e.g. circumcenter of obtuse triangles are outside of the triangle). Each obtuse triangle can always be split into 2 or more right or sharp triangles. They can be removed using the following routines.

pymesh.remove_obtuse_triangles(mesh, max_angle=120, max_iterations=5)

Wrapper function of remove_obtuse_triangles_raw().

Parameters: mesh (Mesh) – Input mesh. max_angle (float) – (optional) Maximum obtuse angle in degrees allowed. All triangle with larger internal angle would be split. Default is 120 degrees. max_iterations (int) – (optional) Number of iterations to run before quitting. Default is 5. 2 values are returned. output_mesh (Mesh): Output mesh. information (dict): A dict of additinal informations. The following fields are defiend in information: num_triangle_split: number of triangles split.
pymesh.remove_obtuse_triangles_raw(vertices, faces, max_angle=120, max_iterations=5)

Remove all obtuse triangles.

Parameters: vetices (numpy.ndarray) – Vertex array with one vertex per row. faces (numpy.ndarray) – Face array with one face per row. max_angle (float) – (optional) Maximum obtuse angle in degrees allowed. All triangle with larger internal angle would be split. Default is 120 degrees. max_iterations (int) – (optional) Number of iterations to run before quitting. Default is 5. 3 values are returned. output_vertices: Output vertex array with one vertex per row. output_faces: Output face array with one face per row. information: A dict of additinal informations. The following fields are defiend in information: num_triangle_split: number of triangles split.

## Remove degenerate triangles¶

Degenerate triangles are triangles with collinear vertices. They have zero area and their normals are undefined. They can be removed using the following routines.

pymesh.remove_degenerated_triangles(mesh, num_iterations=5)

Wrapper function of remove_degenerated_triangles_raw().

Parameters: mesh (Mesh) – Input mesh. 2 values are returned. mesh: A Mesh object without degenerated triangles. info: Additional information dictionary.
pymesh.remove_degenerated_triangles_raw(vertices, faces, num_iterations=5)

Remove degenerated triangles.

Degenerated faces are faces with collinear vertices. It is impossible to compute face normal for them. This method get rid of all degenerated faces. No new vertices will be introduced. Only connectivity is changed.

Parameters: vertices (numpy.ndarray) – Vertex array with one vertex per row. faces (numpy.ndarray) – Face array with one triangle per row. 3 values are returned. output_vertices: Output vertex array, one vertex per row. output_faces: Output face array, one face per row. info: Additional information dict. The following fields are defined in the info dict: ori_face_indices: index array that maps each output face to an input face that contains it.

## Self-intersections¶

Self-intersections are often a problem in geometry processing. They can be detected and resolved with the following routines.

pymesh.detect_self_intersection(mesh)

Detect all self-intersections.

Parameters: mesh (Mesh) – The input mesh. A n by 2 array of face indices. Each row contains the indices of two intersecting faces. $$n$$ is the number of intersecting face pairs. numpy.ndarray
pymesh.resolve_self_intersection(mesh, engine='auto')

Resolve all self-intersections.

Parameters: mesh (Mesh) – The input mesh. Only triangular mesh is supported. engine (string) – (optional) Self-intersection engine. Valid engines include: auto: the default engine (default is igl). igl: libigl’s self-intersection engine A triangular Mesh with all self-intersection resolved. The following per-face scalar field is defined: face_sources: For each output face, this field specifies the index of the corresponding “source face” in the input mesh.

## Separate mesh into disconnected components¶

pymesh.separate_mesh(mesh, connectivity_type='auto')

Split mesh into connected components.

Parameters: mesh (Mesh) – Input mesh. connectivity_type (str) – possible types are auto: Same as face for surface mesh, voxel for voxel mesh. vertex: Group component based on vertex connectivity. face: Group component based on face connectivity. voxel: Group component based on voxel connectivity. A list of meshes, each represent a single connected component. Each output component have the following attributes defined: ori_vertex_index: The input vertex index of each output vertex. ori_elem_index: The input element index of each output element.

## Merge multiple meshes¶

pymesh.merge_meshes(input_meshes)

Merge multiple meshes into a single mesh.

Parameters: input_meshes (list) – a list of input Mesh objects. A Mesh consists of all vertices, faces and voxels from input_meshes. The following mesh attributes are defined: vertex_sources: Indices of source vertices from the input mesh. face_sources: Indices of source faces from the input mesh if the output contains at least 1 face. voxel_sources: Indices of source voxels from the input mesh if the output contains at least 1 voxel.

## Submesh extraction¶

Sometimes, it is useful to extract a local region from a more complex mesh for futher examination. pymesh.submesh() is designed for this task.

pymesh.submesh(mesh, element_indices, num_rings)

Extract a subset of the mesh elements and forming a new mesh.

Parameters: mesh (Mesh) – The input mesh. element_indices (numpy.ndarray) – The indices of selected elements (faces/voxels). num_rings (int) – The number of rings around the selected elements to extract. A Mesh object only containing the selected elements and their local neighborhood up to num_rings rings. The output mesh contains the following attributes: ori_face_index/ori_voxel_index: The original index of each element. ring: Index indicating which ring does each element belongs. The selected elements belongs to the 0-ring.