|
| 1 | +from typing import Optional |
| 2 | + |
1 | 3 | import numpy as np |
2 | 4 | from compas.datastructures import Mesh |
3 | 5 | from compas.plugins import plugin |
@@ -56,7 +58,7 @@ def mesh_remesh( |
56 | 58 | return _meshing.remesh(V, F, target_edge_length, number_of_iterations, do_project) |
57 | 59 |
|
58 | 60 |
|
59 | | -def mesh_project( |
| 61 | +def project_mesh_on_mesh( |
60 | 62 | mesh_source: VerticesFaces, |
61 | 63 | mesh_target: VerticesFaces, |
62 | 64 | use_normals: bool = True, |
@@ -108,6 +110,56 @@ def mesh_project( |
108 | 110 | return Mesh.from_vertices_and_faces(numpy_V_source, F_source) |
109 | 111 |
|
110 | 112 |
|
| 113 | +def project_points_on_mesh( |
| 114 | + points: list[list[float]], |
| 115 | + mesh_target: VerticesFaces, |
| 116 | + normals: Optional[list[list[float]]] = None, |
| 117 | +) -> list[list[float]]: |
| 118 | + """Project points onto mesh_target surface. |
| 119 | +
|
| 120 | + Parameters |
| 121 | + ---------- |
| 122 | + points : list[list[float]] |
| 123 | + The points to project. |
| 124 | + mesh_target : :attr:`compas_cgal.types.VerticesFaces` |
| 125 | + The mesh whose vertices will be projected (source points). |
| 126 | + normals : list[list[float]], optional |
| 127 | + The normals of the points to project. |
| 128 | +
|
| 129 | + Returns |
| 130 | + ------- |
| 131 | + list[list[float]] |
| 132 | + The projected points (vertices on mesh_target surface). |
| 133 | +
|
| 134 | + """ |
| 135 | + V_target, F_target = mesh_target.to_vertices_and_faces(triangulated=True) |
| 136 | + |
| 137 | + # Convert inputs to numpy arrays |
| 138 | + numpy_V_source = np.asarray(points, dtype=np.float64, order="C") |
| 139 | + |
| 140 | + numpy_V_target = np.asarray(V_target, dtype=np.float64, order="C") |
| 141 | + numpy_F_target = np.asarray(F_target, dtype=np.int32, order="C") |
| 142 | + |
| 143 | + # Handle normals calculation |
| 144 | + if normals: |
| 145 | + # Pre-allocate numpy array for normals with correct size |
| 146 | + numpy_N_source = np.zeros((len(points), 3), dtype=np.float64) |
| 147 | + |
| 148 | + # Fill the array with vertex normals |
| 149 | + for i, normal in enumerate(normals): |
| 150 | + numpy_N_source[i, 0] = normal[0] |
| 151 | + numpy_N_source[i, 1] = normal[1] |
| 152 | + numpy_N_source[i, 2] = normal[2] |
| 153 | + else: |
| 154 | + # Don't use normals - create empty array |
| 155 | + numpy_N_source = np.zeros((0, 0), dtype=np.float64) |
| 156 | + |
| 157 | + # Call the C++ function |
| 158 | + _meshing.project(numpy_V_target, numpy_F_target, numpy_V_source, numpy_N_source) |
| 159 | + |
| 160 | + return numpy_V_source |
| 161 | + |
| 162 | + |
111 | 163 | def remesh_dual( |
112 | 164 | mesh: VerticesFaces, |
113 | 165 | length_factor: float = 1.0, |
@@ -137,7 +189,7 @@ def remesh_dual( |
137 | 189 | ------- |
138 | 190 | tuple |
139 | 191 | A tuple containing: |
140 | | - |
| 192 | +
|
141 | 193 | - Remeshed mesh vertices as an Nx3 numpy array. |
142 | 194 | - Remeshed mesh faces as an Mx3 numpy array. |
143 | 195 | - Dual mesh vertices as an Nx3 numpy array. |
|
0 commit comments