Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added simplified borders to map_mesh function.
- Added fixed points to map_mesh function.

### Changed

- Fixed point welding bug in map_mesh function.
- Changed example_isolines to work with the new compas_viewer.
- GA for cibuildwheel, bring back the tessagon test.

### Removed
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(compas_libigl LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)

option(ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
option(ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" ON)
option(MULTITHREADED_COMPILATION "Enable multi-threaded compilation (Ninja only)" ON)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
Expand Down
3 changes: 2 additions & 1 deletion docs/examples/example_isolines.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@

for i, isolines in enumerate(isolines):
color = cmap(values[i], minval, maxval)
viewer.scene.add(isolines, linecolor=color, linewidth=3)
for isoline in isolines:
viewer.scene.add(isoline, linecolor=color, linewidth=3)

viewer.show()
28 changes: 24 additions & 4 deletions docs/examples/example_mapping_patterns.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path

from compas.colors import Color
from compas.geometry import Point
from compas.datastructures import Mesh
from compas_viewer import Viewer
from compas_viewer.config import Config
Expand All @@ -15,16 +16,31 @@

mesh = Mesh.from_obj(Path(__file__).parent.parent.parent / "data" / "minimal_surface.obj")



for vertex in mesh.vertices():
x, y, z = mesh.vertex_attributes(vertex, "xyz") # type: ignore
mesh.vertex_attributes(vertex, "xyz", [x, -z, y])

# ==============================================================================
# Mapping: 3D Mesh, 2D Pattern, UV
# Get Lowest and Highest points
# ==============================================================================

mesh_mapped = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16)
aabb = mesh.aabb()
fixed_vertices = []


for vertex in mesh.vertices():
x, y, z = mesh.vertex_attributes(vertex, "xyz") # type: ignore
if abs(z-aabb.zmin) < 1e-3 or abs(z-aabb.zmax) < 1e-3:
fixed_vertices.append(vertex)

# ==============================================================================
# Mapping: 3D Mesh, 2D Pattern, UV
# ==============================================================================

mesh_mapped0 = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True, fixed_vertices=fixed_vertices)
mesh_mapped1 = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=False)
# ==============================================================================
# Viewer
# ==============================================================================
Expand All @@ -35,7 +51,11 @@

viewer = Viewer(config=config)

# viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
viewer.scene.add(mesh_mapped, name="mesh_mapped", facecolor=Color.red())
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
viewer.scene.add(mesh_mapped0, name="mesh_mapped0", facecolor=Color.red(), show_points=True)
# viewer.scene.add(mesh_mapped1, name="mesh_mapped1", facecolor=Color.blue(), show_points=True, show_faces=False)

for p in fixed_vertices:
viewer.scene.add(mesh.vertex_point(p), pointcolor=Color.red(), pointsize=10)

viewer.show()
2 changes: 1 addition & 1 deletion mesh_flattened.json

Large diffs are not rendered by default.

54 changes: 44 additions & 10 deletions src/compas_libigl/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from compas_libigl._types_std import VectorVectorInt # noqa: F401


def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, tolerance=1e-6):
def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=True, fixed_vertices=None, tolerance=1e-6):
"""
Map a 2D pattern mesh onto a 3D target.

Expand All @@ -36,10 +36,18 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, tolerance=1e-6):
A tuple of (vertices, faces) representing the target mesh.
pattern_mesh : tuple[list[list[float]], list[list[int]]]
A tuple of (vertices, faces) representing the pattern mesh.
clip_boundaries : bool
clip_boundaries : bool, optional
Whether to clip the pattern mesh to the boundaries of the target mesh.
tolerance : float
Default is True.
simplify_borders : bool, optional
Whether to simplify the border of the pattern mesh.
Default is True.
fixed_vertices : list[list[float]], optional
A list of fixed points on the target mesh.
Default is None.
tolerance : float, optional
The tolerance for point comparison, to remove duplicates.
Default is 1e-6.

Returns
-------
Expand All @@ -61,16 +69,30 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, tolerance=1e-6):
f_numpy = np.array(f, dtype=np.int32)
pattern_v_numpy = np.array(pv, dtype=np.float64)

# Handle fixed_vertices - provide empty array if None

fixed_vertices_vectorint = VectorInt()
if fixed_vertices is None:
fixed_vertices_vectorint = VectorInt()
else:
fixed_vertices_vectorint = VectorInt(fixed_vertices)

# Convert pattern_f from Python list to VectorVectorInt which is expected by C++ code

pattern_f_vec = VectorVectorInt()
for face in pf:
pattern_f_vec.append(face)

# Perform the mapping
pv_numpy_copy, pf_numpy_cleaned, p_normals, pattern_is_boundary, pattern_groups = _mapping.map_mesh_with_automatic_parameterization(
v_numpy, f_numpy, pattern_v_numpy, pf, clip_boundaries, tolerance
v_numpy, f_numpy, pattern_v_numpy, pattern_f_vec, clip_boundaries, simplify_borders, fixed_vertices_vectorint, tolerance
)

# Return the result as a tuple
return pv_numpy_copy, pf_numpy_cleaned, p_normals, pattern_is_boundary, pattern_groups


def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16):
def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True, fixed_vertices=None):
"""
Map a 2D pattern mesh onto a 3D target.

Expand Down Expand Up @@ -100,14 +122,24 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter

mesh : compas.datastructures.Mesh
The target mesh.
clip_boundaries : bool
clip_boundaries : bool, optional
Whether to clip the pattern mesh to the boundaries of the target mesh.
tolerance : float
Default is True.
tolerance : float, optional
The tolerance for point comparison, to remove duplicates.
pattern_u : int
Default is 1e-6.
pattern_u : int, optional
The number of pattern vertices in the u direction.
pattern_v : int
Default is 16.
pattern_v : int, optional
The number of pattern vertices in the v direction.
Default is 16.
simplify_borders : bool, optional
Whether to simplify the border of the pattern mesh.
Default is True.
fixed_vertices : list[list[float]], optional
A list of fixed points on the target mesh.
Default is None.

Returns
-------
Expand Down Expand Up @@ -165,6 +197,8 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter
pf = tessagon_mesh["face_list"]

v, f = mesh.to_vertices_and_faces()
mapped_vertices, mapped_faces, mapped_normals, mapped_is_boundary, mapped_groups = map_mesh((v, f), (pv, pf), clip_boundaries=clip_boundaries, tolerance=tolerance)
mapped_vertices, mapped_faces, mapped_normals, mapped_is_boundary, mapped_groups = map_mesh(
(v, f), (pv, pf), clip_boundaries=clip_boundaries, simplify_borders=simplify_borders, fixed_vertices=fixed_vertices, tolerance=tolerance
)

return Mesh.from_vertices_and_faces(mapped_vertices, mapped_faces)
Loading
Loading