55from compas_cgal import _types_std # noqa: F401
66
77from .types import PolylinesNumpySkeleton
8+ from .types import SkeletonVertexMapping
89from .types import VerticesFaces
910
1011
@@ -46,8 +47,8 @@ def mesh_skeleton(mesh: VerticesFaces) -> PolylinesNumpySkeleton:
4647 V_numpy = np .asarray (V , dtype = np .float64 , order = "C" ) # Ensure C-contiguous
4748 F_numpy = np .asarray (F , dtype = np .int32 , order = "C" ) # Ensure C-contiguous
4849
49- # Get start and end points as flattened vectorS
50- start_points , end_points = _skeletonization .mesh_skeleton (V_numpy , F_numpy )
50+ # Get start and end points as flattened vectors
51+ start_points , end_points , _ , _ = _skeletonization .mesh_skeleton (V_numpy , F_numpy )
5152
5253 # Convert flattened vectors to list of point coordinates
5354 edges = []
@@ -57,3 +58,69 @@ def mesh_skeleton(mesh: VerticesFaces) -> PolylinesNumpySkeleton:
5758 edges .append ((start , end ))
5859
5960 return edges
61+
62+
63+ @plugin (category = "mesh" )
64+ def mesh_skeleton_with_mapping (mesh : VerticesFaces ) -> tuple [PolylinesNumpySkeleton , SkeletonVertexMapping ]:
65+ """Compute the geometric skeleton of a triangle mesh with vertex correspondence mapping.
66+
67+ Parameters
68+ ----------
69+ mesh : VerticesFaces
70+ A tuple containing:
71+ * vertices: Nx3 array of vertex coordinates
72+ * faces: Mx3 array of vertex indices
73+
74+ Returns
75+ -------
76+ PolylinesSkeletonWithMapping
77+ A tuple containing:
78+ * edges: List of polylines representing the skeleton edges.
79+ Each polyline is a tuple of start and end point coordinates.
80+ * vertex_indices: List of tuples, each containing two lists of
81+ vertex indices corresponding to the start and end vertices of
82+ each skeleton edge. These are the original mesh vertices that
83+ contracted to form each skeleton vertex.
84+
85+ Raises
86+ ------
87+ TypeError
88+ If the input mesh is not a tuple of vertices and faces.
89+ ValueError
90+ If the vertices array is not Nx3.
91+ If the faces array is not Mx3.
92+ If the face indices are out of range.
93+ If the mesh is not manifold and closed.
94+ RuntimeError
95+ If the mesh contraction fails to converge.
96+
97+ Notes
98+ -----
99+ The input mesh must be manifold and closed.
100+ The skeleton is computed using mean curvature flow.
101+ Each skeleton vertex corresponds to a set of original mesh vertices
102+ that were contracted to that point during the skeletonization process.
103+ (The set might be empty for some skeleton vertices that don't correspond
104+ to any original vertex.)
105+ """
106+ V , F = mesh
107+ V_numpy = np .asarray (V , dtype = np .float64 , order = "C" ) # Ensure C-contiguous
108+ F_numpy = np .asarray (F , dtype = np .int32 , order = "C" ) # Ensure C-contiguous
109+
110+ # Get start and end points and vertex indices
111+ start_points , end_points , start_vertex_indices , end_vertex_indices = _skeletonization .mesh_skeleton (V_numpy , F_numpy )
112+
113+ # Convert flattened vectors to list of point coordinates
114+ edges = []
115+ vertex_indices = []
116+
117+ for i in range (0 , len (start_points ), 3 ):
118+ start = [start_points [i ], start_points [i + 1 ], start_points [i + 2 ]]
119+ end = [end_points [i ], end_points [i + 1 ], end_points [i + 2 ]]
120+ edges .append ((start , end ))
121+
122+ # Process vertex indices - convert VectorInt to Python lists
123+ for start_indices , end_indices in zip (start_vertex_indices , end_vertex_indices ):
124+ vertex_indices .append ((list (start_indices ), list (end_indices )))
125+
126+ return edges , vertex_indices
0 commit comments