Wrapper class for C++ ShortEdgeRemoval class. Attributes: input_mesh: The input mesh. vertices (2D array): the output vertices. faces (2D array): the output faces. Examples: A common usage:: collapser = _EdgeCollapser.create(mesh) c
| 8 | from PyMesh import ShortEdgeRemoval, IsolatedVertexRemoval, FinFaceRemoval |
| 9 | |
| 10 | class _EdgeCollapser(object): |
| 11 | """ Wrapper class for C++ ShortEdgeRemoval class. |
| 12 | |
| 13 | Attributes: |
| 14 | input_mesh: The input mesh. |
| 15 | vertices (2D array): the output vertices. |
| 16 | faces (2D array): the output faces. |
| 17 | |
| 18 | Examples: |
| 19 | A common usage:: |
| 20 | |
| 21 | collapser = _EdgeCollapser.create(mesh) |
| 22 | collapser.keep_features() |
| 23 | collapser.collapse(0.1, None) |
| 24 | print(collapser.vertices) |
| 25 | print(collapser.faces) |
| 26 | """ |
| 27 | @classmethod |
| 28 | def create(cls, mesh): |
| 29 | return _EdgeCollapser(mesh) |
| 30 | |
| 31 | @classmethod |
| 32 | def create_raw(cls, vertices, faces): |
| 33 | mesh = form_mesh(vertices, faces) |
| 34 | return _EdgeCollapser(mesh) |
| 35 | |
| 36 | def __init__(self, mesh): |
| 37 | self.input_mesh = mesh |
| 38 | if self.input_mesh.vertex_per_face != 3: |
| 39 | raise RuntimeError("Only triangle mesh is supported! " |
| 40 | "Input has {} vertices per face".format( |
| 41 | self.input_mesh.vertex_per_face)) |
| 42 | self.logger = logging.getLogger(__name__) |
| 43 | self.importance = None |
| 44 | |
| 45 | @timethis |
| 46 | def keep_features(self): |
| 47 | """ Preserve sharp edges and boundaries. |
| 48 | """ |
| 49 | if not self.input_mesh.has_attribute("vertex_dihedral_angle"): |
| 50 | self.input_mesh.add_attribute("vertex_dihedral_angle") |
| 51 | dihedral_angle = self.input_mesh.get_attribute("vertex_dihedral_angle") |
| 52 | self.importance = np.round(dihedral_angle * 4 / math.pi).astype(int) |
| 53 | |
| 54 | # keep boundary. |
| 55 | bd_vertices = self.input_mesh.boundary_vertices |
| 56 | self.importance[bd_vertices] = 10 |
| 57 | |
| 58 | @timethis |
| 59 | def collapse(self, abs_threshold, rel_threshold): |
| 60 | """ Note this method remove all edges with length less than threshold. |
| 61 | This could result in a non-manifold mesh. |
| 62 | """ |
| 63 | min_edge_length = abs_threshold |
| 64 | if rel_threshold is not None: |
| 65 | ave_edge_len = self.__get_ave_edge_length() |
| 66 | min_edge_length = rel_threshold * ave_edge_len |
| 67 | self.logger.info("Minimum edge threshold: {:.3}".format(min_edge_length)) |
no outgoing calls
no test coverage detected