Skip to content

Commit 2c24438

Browse files
author
pv
committed
ADD documentation, test.
1 parent 9b6b49f commit 2c24438

File tree

14 files changed

+206
-795
lines changed

14 files changed

+206
-795
lines changed

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,4 @@ add_nanobind_module(_massmatrix src/massmatrix.cpp)
172172
add_nanobind_module(_meshing src/meshing.cpp)
173173
add_nanobind_module(_parametrisation src/parametrisation.cpp)
174174
add_nanobind_module(_planarize src/planarize.cpp)
175-
add_nanobind_module(_patternmap src/patternmap.cpp)
176175
add_nanobind_module(_mapping src/mapping.cpp)

docs/_images/example_mapping.png

174 KB
Loading
Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
from compas.datastructures import Mesh
2-
from tessagon.types.hex_tessagon import HexTessagon
3-
from tessagon.adaptors.list_adaptor import ListAdaptor
42
from compas_viewer import Viewer
5-
import compas_libigl as igl
6-
from compas_libigl import _mapping
7-
import numpy as np
3+
from tessagon.adaptors.list_adaptor import ListAdaptor
4+
from tessagon.types.hex_tessagon import HexTessagon
5+
from compas.colors import Color
86

9-
viewer = Viewer()
7+
import compas_libigl as igl
108

119
# ==============================================================================
1210
# Input geometry: 3D Mesh
1311
# ==============================================================================
1412

15-
# Load the mesh
1613
mesh = Mesh.from_obj("data/minimal_surface.obj")
1714
for key, attr in mesh.vertices(True):
1815
y = attr["y"]
1916
attr["y"] = -attr["z"]
2017
attr["z"] = y
18+
mesh.translate([2, 2, 0.5])
2119

2220
v, f = mesh.to_vertices_and_faces()
2321

24-
viewer.scene.add(mesh, name="mesh")
2522

2623
# ==============================================================================
2724
# Input geometry: 2D Pattern creation using Tessagon library, can be other mesh.
@@ -44,57 +41,51 @@
4441

4542

4643
# ==============================================================================
47-
# Parametrization: choose between simple, lcsm and harmonic methods.
44+
# Place the pattern mesh at the center of the 3D mesh
45+
# ==============================================================================
46+
pattern2d = Mesh.from_vertices_and_faces(pv, pf)
47+
c = pattern2d.aabb().corner(0)
48+
pattern2d.translate([-c[0], -c[1], -c[2]])
49+
pv, pf = pattern2d.to_vertices_and_faces()
50+
51+
52+
# ==============================================================================
53+
# Parametrization
4854
# ==============================================================================
4955

50-
uv = igl.trimesh_simple((v, f))
51-
# uv = igl.trimesh_lscm((v, f))
52-
# uv = igl.trimesh_harmonic((v, f))
56+
uv = igl.trimesh_lscm((v, f))
5357

5458
mesh_flattened = mesh.copy()
5559
mesh_flattened.vertices_attribute("z", 0)
5660

5761
for i in range(mesh.number_of_vertices()):
5862
mesh_flattened.vertex_attributes(i, "xy", uv[i])
5963

60-
viewer.scene.add(mesh_flattened, name="mesh_flattened")
61-
6264
# ==============================================================================
63-
# Mapping: 3D Mesh, 2D Pattern, UV
64-
# Eigen::Ref<const compas::RowMatrixXd> v,
65-
# Eigen::Ref<const compas::RowMatrixXi> f,
66-
# Eigen::Ref<const compas::RowMatrixXd> uv,
67-
# Eigen::Ref<compas::RowMatrixXd> pattern_v,
68-
# Eigen::Ref<const compas::RowMatrixXi> pattern_f,
69-
# Eigen::Ref<const compas::RowMatrixXd> pattern_uv,
70-
# std::vector<std::vector<int>>& pattern_polygonal_faces
65+
# Rescale the flattened uv mesh to 1x1 scale
7166
# ==============================================================================
67+
box = mesh_flattened.aabb()
68+
c = box.corner(0)
69+
mesh_flattened.translate([-c[0], -c[1], -c[2]])
70+
mesh_flattened.scale(1.0 / box.xsize, 1.0 / box.ysize, 1)
7271

73-
v_numpy = np.array(v, dtype=np.float64)
74-
f_numpy = np.array(f, dtype=np.int32)
75-
uv_numpy = np.array(uv, dtype=np.float64)
76-
pattern_v_numpy = np.array(pv, dtype=np.float64)
77-
pattern_f_numpy = np.array(pf, dtype=np.int32)
78-
pattern_uv = igl.trimesh_simple((pv, pf))
79-
pattern_uv_numpy = np.array(pattern_uv, dtype=np.float64)
80-
pattern_polygonal_faces = pf
81-
82-
print("Before mapping")
83-
print(pattern_v_numpy[0])
84-
_mapping.mapMesh3D_AABB(v_numpy, f_numpy, uv_numpy, pattern_v_numpy, pattern_f_numpy, pattern_uv_numpy, pattern_polygonal_faces)
85-
print("After mapping")
86-
87-
for i in range(100):
88-
print(pattern_v_numpy[i])
89-
90-
mapped_mesh = Mesh.from_vertices_and_faces(pattern_v_numpy, pattern_f_numpy)
91-
viewer.scene.add(mapped_mesh, name="mapped_mesh")
72+
for i in range(mesh.number_of_vertices()):
73+
uv[i] = mesh_flattened.vertex_attributes(i, "xy")
9274

75+
# ==============================================================================
76+
# Mapping: 3D Mesh, 2D Pattern, UV
77+
# ==============================================================================
9378

79+
p_uv = igl.trimesh_simple((pv, pf))
80+
mesh_mapped = igl.map_mesh(v, f, uv, pv, pf, p_uv)
9481

9582
# ==============================================================================
9683
# Viewer
9784
# ==============================================================================
9885

99-
100-
viewer.show()
86+
viewer = Viewer()
87+
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
88+
viewer.scene.add(pattern2d, name="pattern2d")
89+
viewer.scene.add(mesh_flattened, name="mesh_flattened")
90+
viewer.scene.add(mesh_mapped, name="mesh_mapped", facecolor=Color.red())
91+
viewer.show()

docs/examples/example_mapping.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
********************************************************************************
2+
Mapping
3+
********************************************************************************
4+
5+
.. figure:: /_images/example_mapping.png
6+
:figclass: figure
7+
:class: figure-img img-fluid
8+
9+
.. literalinclude:: example_mapping.py
10+
:language: python

requirements-dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ scikit-build-core[pyproject] >=0.10
1313
twine
1414
wheel
1515
setuptools
16-
cibuildwheel==2.23.1
16+
cibuildwheel==2.23.1
17+
tessagon

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
compas >=2.0.0
2+
tessagon

src/compas_libigl/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
from .isolines import trimesh_isolines, groupsort_isolines
99
from .massmatrix import trimesh_massmatrix
1010
from .parametrisation import trimesh_harmonic, trimesh_lscm, trimesh_simple
11-
from .mapping import trimesh_map_simple, trimesh_map_aabb
1211
from .planarize import quadmesh_planarize
1312
from .meshing import trimesh_remesh_along_isoline, trimesh_remesh_along_isolines
13+
from .mapping import map_mesh
1414

1515

1616
__author__ = ["tom van mele", "petras vestartas"]
@@ -123,4 +123,5 @@ def get_armadillo():
123123
"quadmesh_planarize",
124124
"trimesh_remesh_along_isoline",
125125
"trimesh_remesh_along_isolines",
126+
"map_mesh",
126127
]

src/compas_libigl/mapping.py

Lines changed: 26 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,42 @@
11
import numpy as np
2+
from compas.datastructures import Mesh
23

34
from compas_libigl import _mapping
45

56

6-
def trimesh_map_simple(M_target, M_pattern, UV_target):
7+
def map_mesh(v, f, uv, pv, pf, p_uv):
78
"""Map a 2D pattern mesh onto a 3D target mesh using simple UV parameterization.
89
910
Parameters
1011
----------
11-
M_target : tuple[list[list[float]], list[list[int]]]
12-
A target mesh represented by a tuple of (vertices, faces)
13-
where vertices are 3D points and faces are triangles
14-
M_pattern : tuple[list[list[float]], list[list[int]]]
15-
A pattern mesh represented by a tuple of (vertices, faces)
16-
where vertices are 2D or 3D points and faces are triangles
17-
UV_target : list[list[float]]
18-
UV coordinates for the target mesh vertices
12+
v : list[list[float]]
13+
The vertices of the target mesh.
14+
f : list[list[int]]
15+
The faces of the target mesh.
16+
uv : list[list[float]]
17+
The UV coordinates of the target mesh.
18+
pv : list[list[float]]
19+
The vertices of the pattern mesh.
20+
pf : list[list[int]]
21+
The faces of the pattern mesh.
22+
p_uv : list[list[float]]
23+
The UV coordinates of the pattern mesh.
1924
2025
Returns
2126
-------
22-
tuple[list[list[float]], list[list[int]]]
23-
The mapped pattern mesh as a tuple of (vertices, faces)
27+
pattern_mapped_cleaned : compas.datastructures.Mesh
28+
The mapped pattern mesh.
2429
"""
25-
V_target, F_target = M_target
26-
V_pattern, F_pattern = M_pattern
27-
28-
V_target = np.asarray(V_target, dtype=np.float64)
29-
F_target = np.asarray(F_target, dtype=np.int32)
30-
V_pattern = np.asarray(V_pattern, dtype=np.float64)
31-
F_pattern = np.asarray(F_pattern, dtype=np.int32)
32-
UV_target = np.asarray(UV_target, dtype=np.float64)
33-
34-
V_result, F_result = _mapping.mapMesh3D_simple(
35-
V_target, F_target, V_pattern, F_pattern, UV_target)
36-
37-
return V_result.tolist(), F_result.tolist()
3830

31+
v_numpy = np.array(v, dtype=np.float64)
32+
f_numpy = np.array(f, dtype=np.int32)
33+
uv_numpy = np.array(uv, dtype=np.float64)
34+
pattern_v_numpy = np.array(pv, dtype=np.float64)
35+
pattern_f_numpy = np.array(pf, dtype=np.int32)
36+
p_uv_numpy = np.array(p_uv, dtype=np.float64)
3937

40-
def trimesh_map_aabb(M_target, M_pattern, UV_target):
41-
"""Map a 2D pattern mesh onto a 3D target mesh using AABB tree for faster point lookup.
38+
# Call the mapping function with the new signature (returns a tuple)
39+
pattern_f_numpy_cleaned = _mapping.map_mesh(v_numpy, f_numpy, uv_numpy, pattern_v_numpy, pattern_f_numpy, p_uv_numpy)
4240

43-
Parameters
44-
----------
45-
M_target : tuple[list[list[float]], list[list[int]]]
46-
A target mesh represented by a tuple of (vertices, faces)
47-
where vertices are 3D points and faces are triangles
48-
M_pattern : tuple[list[list[float]], list[list[int]]]
49-
A pattern mesh represented by a tuple of (vertices, faces)
50-
where vertices are 2D or 3D points and faces are triangles
51-
UV_target : list[list[float]]
52-
UV coordinates for the target mesh vertices
53-
54-
Returns
55-
-------
56-
tuple[list[list[float]], list[list[int]]]
57-
The mapped pattern mesh as a tuple of (vertices, faces)
58-
"""
59-
V_target, F_target = M_target
60-
V_pattern, F_pattern = M_pattern
61-
62-
V_target = np.asarray(V_target, dtype=np.float64)
63-
F_target = np.asarray(F_target, dtype=np.int32)
64-
V_pattern = np.asarray(V_pattern, dtype=np.float64)
65-
F_pattern = np.asarray(F_pattern, dtype=np.int32)
66-
UV_target = np.asarray(UV_target, dtype=np.float64)
67-
68-
V_result, F_result = _mapping.mapMesh3D_AABB(
69-
V_target, F_target, V_pattern, F_pattern, UV_target)
70-
71-
return V_result.tolist(), F_result.tolist()
41+
pattern_mapped_cleaned = Mesh.from_vertices_and_faces(pattern_v_numpy, pattern_f_numpy_cleaned)
42+
return pattern_mapped_cleaned

src/compas_libigl/parametrisation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def trimesh_harmonic(M):
2525
F = np.asarray(F, dtype=np.int32)
2626
return _parametrisation.harmonic(V, F)
2727

28+
2829
@plugin(category="trimesh")
2930
def trimesh_lscm(M):
3031
"""Compute the least squares conformal map of a triangle mesh.
@@ -47,7 +48,6 @@ def trimesh_lscm(M):
4748
return _parametrisation.lscm(V, F)
4849

4950

50-
5151
@plugin(category="trimesh")
5252
def trimesh_simple(M):
5353
"""Compute the least squares conformal map of a triangle mesh.

0 commit comments

Comments
 (0)