Skip to content

Commit 251038c

Browse files
ADD project points and project mesh.
1 parent 9b4c528 commit 251038c

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

docs/api/compas_cgal.meshing.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ compas_cgal.meshing
1010

1111
mesh_remesh
1212
remesh_dual
13-
mesh_project
13+
project_mesh_on_mesh
14+
project_points_on_mesh

docs/examples/example_projection.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from pathlib import Path
22

3+
from compas.geometry import Point
34
from compas.datastructures import Mesh
45
from compas_viewer import Viewer
56

6-
from compas_cgal.meshing import mesh_project
7+
from compas_cgal.meshing import project_mesh_on_mesh, project_points_on_mesh
78

89

910
# Mesh to project
@@ -14,7 +15,14 @@
1415
input_file_1 = Path(__file__).parent.parent.parent / "data" / "rhinovault_mesh_1.ply"
1516
mesh_1 = Mesh.from_ply(input_file_1)
1617

17-
mesh_result = mesh_project(mesh_0, mesh_1, use_normals=False)
18+
mesh_result = project_mesh_on_mesh(mesh_0, mesh_1, use_normals=False)
19+
20+
# Points with normals to project
21+
v, f = mesh_0.to_vertices_and_faces()
22+
normals = []
23+
for i in range(len(v)):
24+
normals.append(mesh_0.vertex_normal(i))
25+
points_result = project_points_on_mesh(v, mesh_1, normals)
1826

1927
# ==============================================================================
2028
# Visualize
@@ -27,5 +35,7 @@
2735
viewer.scene.add(mesh_0, name="source mesh_0", show_faces=False)
2836
viewer.scene.add(mesh_1, name="target mesh_1", show_faces=False)
2937
viewer.scene.add(mesh_result, name="projected mesh_result", color=[255, 0, 0])
38+
for i, point in enumerate(points_result):
39+
viewer.scene.add(Point(*point), name=f"point_{i}", color=[0, 255, 0])
3040

3141
viewer.show()

src/compas_cgal/meshing.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
13
import numpy as np
24
from compas.datastructures import Mesh
35
from compas.plugins import plugin
@@ -56,7 +58,7 @@ def mesh_remesh(
5658
return _meshing.remesh(V, F, target_edge_length, number_of_iterations, do_project)
5759

5860

59-
def mesh_project(
61+
def project_mesh_on_mesh(
6062
mesh_source: VerticesFaces,
6163
mesh_target: VerticesFaces,
6264
use_normals: bool = True,
@@ -108,6 +110,56 @@ def mesh_project(
108110
return Mesh.from_vertices_and_faces(numpy_V_source, F_source)
109111

110112

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+
111163
def remesh_dual(
112164
mesh: VerticesFaces,
113165
length_factor: float = 1.0,
@@ -137,7 +189,7 @@ def remesh_dual(
137189
-------
138190
tuple
139191
A tuple containing:
140-
192+
141193
- Remeshed mesh vertices as an Nx3 numpy array.
142194
- Remeshed mesh faces as an Mx3 numpy array.
143195
- Dual mesh vertices as an Nx3 numpy array.

tests/test_projection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pathlib import Path
22
from compas.datastructures import Mesh
3-
from compas_cgal.meshing import mesh_project
3+
from compas_cgal.meshing import project_mesh_on_mesh
44

55

66
def mesh_projection():
@@ -12,6 +12,6 @@ def mesh_projection():
1212
input_file_1 = Path(__file__).parent.parent.parent / "data" / "rhinovault_mesh_1.ply"
1313
mesh_1 = Mesh.from_ply(input_file_1)
1414

15-
mesh_result = mesh_project(mesh_0, mesh_1, use_normals=False)
15+
mesh_result = project_mesh_on_mesh(mesh_0, mesh_1, use_normals=False)
1616

1717
assert mesh_result.number_of_vertices() == mesh_0.number_of_vertices()

0 commit comments

Comments
 (0)