Skip to content

Commit 7633300

Browse files
ADD mapping fixed points option.
1 parent 8b4ee00 commit 7633300

File tree

10 files changed

+147
-107
lines changed

10 files changed

+147
-107
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818

1919
### Added
2020

21+
- Added simplified borders to map_mesh function.
22+
- Added fixed points to map_mesh function.
23+
2124
### Changed
2225

2326
- Fixed point welding bug in map_mesh function.
27+
- Changed example_isolines to work with the new compas_viewer.
2428

2529
### Removed
2630

CMakeLists.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,13 @@ endfunction()
152152
# === Add your modules ===
153153
add_nanobind_module(_nanobind src/nanobind.cpp)
154154
add_nanobind_module(_types_std src/types_std.cpp)
155-
# add_nanobind_module(_boundaries src/boundaries.cpp)
156-
# add_nanobind_module(_curvature src/curvature.cpp)
157-
# add_nanobind_module(_geodistance src/geodistance.cpp)
158-
# add_nanobind_module(_intersections src/intersections.cpp)
159-
# add_nanobind_module(_isolines src/isolines.cpp)
160-
# add_nanobind_module(_massmatrix src/massmatrix.cpp)
161-
# add_nanobind_module(_meshing src/meshing.cpp)
162-
# add_nanobind_module(_parametrisation src/parametrisation.cpp)
163-
# add_nanobind_module(_planarize src/planarize.cpp)
155+
add_nanobind_module(_boundaries src/boundaries.cpp)
156+
add_nanobind_module(_curvature src/curvature.cpp)
157+
add_nanobind_module(_geodistance src/geodistance.cpp)
158+
add_nanobind_module(_intersections src/intersections.cpp)
159+
add_nanobind_module(_isolines src/isolines.cpp)
160+
add_nanobind_module(_massmatrix src/massmatrix.cpp)
161+
add_nanobind_module(_meshing src/meshing.cpp)
162+
add_nanobind_module(_parametrisation src/parametrisation.cpp)
163+
add_nanobind_module(_planarize src/planarize.cpp)
164164
add_nanobind_module(_mapping src/mapping.cpp)

docs/examples/example_isolines.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
for i, isolines in enumerate(isolines):
5555
color = cmap(values[i], minval, maxval)
56-
viewer.scene.add(isolines, linecolor=color, linewidth=3)
56+
for isoline in isolines:
57+
viewer.scene.add(isoline, linecolor=color, linewidth=3)
5758

5859
viewer.show()

docs/examples/example_mapping_patterns.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from pathlib import Path
22

33
from compas.colors import Color
4+
from compas.geometry import Point
45
from compas.datastructures import Mesh
56
from compas_viewer import Viewer
67
from compas_viewer.config import Config
@@ -15,15 +16,30 @@
1516

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

19+
20+
1821
for vertex in mesh.vertices():
1922
x, y, z = mesh.vertex_attributes(vertex, "xyz") # type: ignore
2023
mesh.vertex_attributes(vertex, "xyz", [x, -z, y])
2124

25+
# ==============================================================================
26+
# Get Lowest and Highest points
27+
# ==============================================================================
28+
29+
aabb = mesh.aabb()
30+
fixed_points = []
31+
32+
33+
for vertex in mesh.vertices():
34+
x, y, z = mesh.vertex_attributes(vertex, "xyz") # type: ignore
35+
if abs(z-aabb.zmin) < 1e-3 or abs(z-aabb.zmax) < 1e-3:
36+
fixed_points.append(vertex)
37+
2238
# ==============================================================================
2339
# Mapping: 3D Mesh, 2D Pattern, UV
2440
# ==============================================================================
2541

26-
mesh_mapped0 = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True)
42+
mesh_mapped0 = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True, fixed_points=fixed_points)
2743
mesh_mapped1 = map_pattern_to_mesh("ZigZag", mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=False)
2844
# ==============================================================================
2945
# Viewer
@@ -35,9 +51,11 @@
3551

3652
viewer = Viewer(config=config)
3753

38-
# viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
54+
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
3955
viewer.scene.add(mesh_mapped0, name="mesh_mapped0", facecolor=Color.red(), show_points=True)
40-
viewer.scene.add(mesh_mapped1, name="mesh_mapped1", facecolor=Color.blue(), show_points=True, show_faces=False)
56+
# viewer.scene.add(mesh_mapped1, name="mesh_mapped1", facecolor=Color.blue(), show_points=True, show_faces=False)
4157

58+
for p in fixed_points:
59+
viewer.scene.add(mesh.vertex_point(p), pointcolor=Color.red(), pointsize=10)
4260

4361
viewer.show()

mesh_flattened.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ CMAKE_POLICY_DEFAULT_CMP0135 = "NEW"
7575

7676
[tool.cibuildwheel]
7777
build-verbosity = 3
78-
test-requires = ["numpy", "compas", "pytest", "build"]
78+
test-requires = ["numpy", "compas", "pytest", "build", "tessagon"]
7979
test-command = "pip install numpy compas && pip list && pytest {project}/tests"
8080
build-frontend = "pip"
8181
manylinux-x86_64-image = "manylinux2014"

src/compas_libigl/mapping.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from compas_libigl._types_std import VectorVectorInt # noqa: F401
2727

2828

29-
def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=True, tolerance=1e-6):
29+
def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=True, fixed_points=None, tolerance=1e-6):
3030
"""
3131
Map a 2D pattern mesh onto a 3D target.
3232
@@ -40,6 +40,8 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=T
4040
Whether to clip the pattern mesh to the boundaries of the target mesh.
4141
simplify_borders : bool
4242
Whether to simplify the border of the pattern mesh.
43+
fixed_points : list[list[float]]
44+
A list of fixed points on the target mesh.
4345
tolerance : float
4446
The tolerance for point comparison, to remove duplicates.
4547
@@ -63,16 +65,30 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=T
6365
f_numpy = np.array(f, dtype=np.int32)
6466
pattern_v_numpy = np.array(pv, dtype=np.float64)
6567

68+
# Handle fixed_points - provide empty array if None
69+
70+
fixed_points_vectorint = VectorInt()
71+
if fixed_points is None:
72+
fixed_points_vectorint = VectorInt()
73+
else:
74+
fixed_points_vectorint = VectorInt(fixed_points)
75+
76+
# Convert pattern_f from Python list to VectorVectorInt which is expected by C++ code
77+
78+
pattern_f_vec = VectorVectorInt()
79+
for face in pf:
80+
pattern_f_vec.append(face)
81+
6682
# Perform the mapping
6783
pv_numpy_copy, pf_numpy_cleaned, p_normals, pattern_is_boundary, pattern_groups = _mapping.map_mesh_with_automatic_parameterization(
68-
v_numpy, f_numpy, pattern_v_numpy, pf, clip_boundaries, simplify_borders, tolerance
84+
v_numpy, f_numpy, pattern_v_numpy, pattern_f_vec, clip_boundaries, simplify_borders, fixed_points_vectorint, tolerance
6985
)
7086

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

7490

75-
def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True):
91+
def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, pattern_u=16, pattern_v=16, simplify_borders=True, fixed_points=None):
7692
"""
7793
Map a 2D pattern mesh onto a 3D target.
7894
@@ -112,6 +128,8 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter
112128
The number of pattern vertices in the v direction.
113129
simplify_borders : bool
114130
Whether to simplify the border of the pattern mesh.
131+
fixed_points : list[list[float]]
132+
A list of fixed points on the target mesh.
115133
116134
Returns
117135
-------
@@ -169,6 +187,8 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter
169187
pf = tessagon_mesh["face_list"]
170188

171189
v, f = mesh.to_vertices_and_faces()
172-
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, tolerance=tolerance)
190+
mapped_vertices, mapped_faces, mapped_normals, mapped_is_boundary, mapped_groups = map_mesh(
191+
(v, f), (pv, pf), clip_boundaries=clip_boundaries, simplify_borders=simplify_borders, fixed_points=fixed_points, tolerance=tolerance
192+
)
173193

174194
return Mesh.from_vertices_and_faces(mapped_vertices, mapped_faces)

src/mapping.cpp

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
#include "mapping.hpp"
2-
#include <algorithm>
3-
#include <iostream>
4-
#include <iomanip>
5-
#include <cmath>
6-
#include <unordered_set>
72

83
// Custom hash function for tuple
94
struct TupleHash {
@@ -99,7 +94,7 @@ std::vector<std::vector<int>> map_mesh_cropped(
9994
}
10095

10196
// Update pattern vertex position through barycentric interpolation, comment this out if you keep 2D pattern
102-
// pattern_v.row(id) = A * L(0, 0) + B * L(0, 1) + C * L(0, 2);
97+
pattern_v.row(id) = A * L(0, 0) + B * L(0, 1) + C * L(0, 2);
10398

10499
// If normals are requested, interpolate them using the same barycentric coordinates
105100
if (compute_normals) {
@@ -177,9 +172,18 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, std::vector<bool>
177172
const std::vector<std::vector<int>>& pattern_f,
178173
bool clip_boundaries,
179174
bool simplify_borders,
175+
std::vector<int>& fixed_points,
180176
double tolerance
181177
)
182178
{
179+
180+
////////////////////////////////////////////////////////////////////////////////////////
181+
// Fixed points
182+
////////////////////////////////////////////////////////////////////////////////////////
183+
Clipper2Lib::PathD fixed;
184+
for (const auto &point_id : fixed_points){
185+
fixed.emplace_back(Clipper2Lib::PointD(flattned_target_uv(point_id, 0), flattned_target_uv(point_id, 1)));
186+
}
183187

184188
////////////////////////////////////////////////////////////////////////////////////////
185189
// Get Boundary polygon of a Mesh as Clipper Path.
@@ -302,6 +306,7 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, std::vector<bool>
302306
simplified_paths[0].reserve(subject[0].size());
303307

304308
for (const auto &p : solution[0]){ // iterate the points of the intersection polygon
309+
305310
// First check if point is close to any vertex (corner)
306311
bool point_added = false;
307312
for(size_t i = 0; i < subject[0].size(); i++){
@@ -313,6 +318,19 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, std::vector<bool>
313318
break;
314319
}
315320
}
321+
322+
// Check if point is close to any fixed point
323+
for(size_t i = 0; i < fixed.size(); i++){
324+
double fx = fixed[i].x;
325+
double fy = fixed[i].y;
326+
double dx = p.x - fx;
327+
double dy = p.y - fy;
328+
if (dx*dx + dy*dy < tolerance*tolerance){
329+
simplified_paths[0].push_back(p);
330+
point_added = true;
331+
break;
332+
}
333+
}
316334

317335
// If not close to a vertex, check if close to any edge
318336
if (!point_added) {
@@ -431,46 +449,20 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, compas::RowMatrix
431449
const std::vector<std::vector<int>>& pattern_f,
432450
bool clip_boundaries,
433451
bool simplify_borders,
452+
std::vector<int>& fixed_points,
434453
double tolerance)
435454
{
436455

437456

457+
458+
438459
// Compute target mesh UV parameterization using LSCM
439460
Eigen::MatrixXd target_uv;
440461

441462
// Find the open boundary
442463
Eigen::VectorXi B;
443464
igl::boundary_loop(target_f, B);
444465

445-
// Get Boundary vertices
446-
std::vector<Eigen::Vector3d> corner_vertex_coords;
447-
448-
std::vector<std::vector<int>> VV;
449-
igl::adjacency_list(target_f, VV);
450-
451-
// Create a set of boundary vertices for faster lookup
452-
std::unordered_set<int> boundary_set;
453-
for (int i = 0; i < B.size(); i++) {
454-
boundary_set.insert(B(i));
455-
}
456-
457-
for (int i = 0; i < B.size(); i++) {
458-
int v = B(i);
459-
int boundary_valence = 0;
460-
for (int neighbor : VV[v])
461-
if (boundary_set.count(neighbor) > 0)
462-
boundary_valence++;
463-
464-
if (boundary_valence < 2) {
465-
Eigen::Vector3d vertex_pos(target_v(v, 0), target_v(v, 1), target_v(v, 2));
466-
corner_vertex_coords.push_back(vertex_pos);
467-
std::cout << "Corner vertex " << v << " at position ("
468-
<< target_v(v, 0) << ", "
469-
<< target_v(v, 1) << ", "
470-
<< target_v(v, 2) << ")" << std::endl;
471-
}
472-
}
473-
474466
// Fix two points on the boundary
475467
Eigen::VectorXi fixed(2, 1);
476468
fixed(0) = B(0);
@@ -494,7 +486,7 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, compas::RowMatrix
494486

495487

496488
// Clip the pattern
497-
auto [clipped_pattern_v, clipped_pattern_f, clipped_pattern_is_boundary, clipped_pattern_groups] = eigen_to_clipper(target_uv, target_f, pattern_v, pattern_f, clip_boundaries, simplify_borders, tolerance);
489+
auto [clipped_pattern_v, clipped_pattern_f, clipped_pattern_is_boundary, clipped_pattern_groups] = eigen_to_clipper(target_uv, target_f, pattern_v, pattern_f, clip_boundaries, simplify_borders, fixed_points, tolerance);
498490

499491
Eigen::MatrixXd clipped_pattern_uv;
500492
clipped_pattern_uv.setZero();
@@ -531,6 +523,7 @@ NB_MODULE(_mapping, m)
531523
"pattern_f"_a,
532524
"clip_boundaries"_a,
533525
"simplify_borders"_a,
526+
"fixed_points"_a,
534527
"tolerance"_a
535528
);
536529
}

src/mapping.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ bool paths_intersect(const Clipper2Lib::PathsD& paths1, const Clipper2Lib::Paths
7474
* @param pattern_f The pattern mesh face indices.
7575
* @param clip_boundaries Whether to clip the pattern mesh to the boundaries of the target mesh.
7676
* @param simplify_borders Whether to simplify the border of the pattern mesh.
77+
* @param fixed_points fixed points on the target mesh
7778
* @param tolerance The tolerance for point comparison, to remove duplicates.
7879
* @return A tuple of the clipped pattern mesh vertex coordinates and face indices.
7980
*/
@@ -85,6 +86,7 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, std::vector<bool>
8586
const std::vector<std::vector<int>>& pattern_f,
8687
bool clip_boundaries,
8788
bool simplify_borders,
89+
std::vector<int>& fixed_points,
8890
double tolerance = 1e-6
8991
) ;
9092

@@ -99,6 +101,7 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, std::vector<bool>
99101
* @param pattern_f vector of vectors of int of pattern mesh triangle indices
100102
* @param clip_boundaries whether to clip the pattern mesh to the boundaries of the target mesh
101103
* @param simplify_borders whether to simplify the border of the pattern mesh
104+
* @param fixed_points fixed points on the target mesh
102105
* @param tolerance tolerance for point comparison, to remove duplicates
103106
* @return A tuple containing the mapped pattern vertices, faces, and vertex normal vectors.
104107
*/
@@ -109,5 +112,6 @@ std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>, compas::RowMatrix
109112
const std::vector<std::vector<int>>& pattern_f,
110113
bool clip_boundaries,
111114
bool simplify_borders,
115+
std::vector<int>& fixed_points,
112116
double tolerance = 1e-6
113117
);

0 commit comments

Comments
 (0)