Skip to content

Commit c3fae6f

Browse files
ADD 2D polygons winding directions.
1 parent fc82f48 commit c3fae6f

File tree

4 files changed

+32
-17
lines changed

4 files changed

+32
-17
lines changed

CHANGELOG.md

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

1919
### Added
2020

21+
* Add winding check in map_mesh function.
22+
2123
### Changed
2224

2325
* Added meshpatter unify_cycles from COMPAS, LIBIGL has only triangle BFS.

mesh_flattened.json

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

src/compas_libigl/mapping.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
}
4545

4646

47-
def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=True, fixed_vertices=None, tolerance=1e-6, unify_cycles=True):
47+
def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=True, fixed_vertices=None, tolerance=1e-6):
4848
"""
4949
Map a 2D pattern mesh onto a 3D target.
5050
@@ -66,9 +66,6 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=T
6666
tolerance : float, optional
6767
The tolerance for point comparison, to remove duplicates.
6868
Default is 1e-6.
69-
unify_cycles : bool, optional
70-
Whether to unify cycles of the pattern mesh.
71-
Default is True.
7269
7370
Returns
7471
-------
@@ -109,17 +106,11 @@ def map_mesh(target_mesh, pattern_mesh, clip_boundaries=True, simplify_borders=T
109106
v_numpy, f_numpy, pattern_v_numpy, pattern_f_vec, clip_boundaries, simplify_borders, fixed_vertices_vectorint, tolerance
110107
)
111108

112-
# LIBIGL has no BFS orienting for polygons, only triangles, so we copy here data several times:
113-
if unify_cycles:
114-
mesh = Mesh.from_vertices_and_faces(pv_numpy_copy, pf_numpy_cleaned)
115-
mesh.unify_cycles()
116-
pv_numpy_copy, pf_numpy_cleaned = mesh.to_vertices_and_faces()
117-
118109
# Return the result as a tuple
119110
return pv_numpy_copy, pf_numpy_cleaned, p_normals, pattern_is_boundary, pattern_groups
120111

121112

122-
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, unify_cycles=True):
113+
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):
123114
"""
124115
Map a 2D pattern mesh onto a 3D target.
125116
@@ -167,9 +158,7 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter
167158
fixed_vertices : list[list[float]], optional
168159
A list of fixed points on the target mesh.
169160
Default is None.
170-
unify_cycles : bool, optional
171-
Whether to unify cycles of the pattern mesh.
172-
Default is True.
161+
173162
Returns
174163
-------
175164
compas.datastructures.Mesh
@@ -206,7 +195,7 @@ def map_pattern_to_mesh(name, mesh, clip_boundaries=True, tolerance=1e-6, patter
206195

207196
v, f = mesh.to_vertices_and_faces()
208197
mapped_vertices, mapped_faces, mapped_normals, mapped_is_boundary, mapped_groups = map_mesh(
209-
(v, f), (pv, pf), clip_boundaries=clip_boundaries, simplify_borders=simplify_borders, fixed_vertices=fixed_vertices, tolerance=tolerance, unify_cycles=unify_cycles
198+
(v, f), (pv, pf), clip_boundaries=clip_boundaries, simplify_borders=simplify_borders, fixed_vertices=fixed_vertices, tolerance=tolerance
210199
)
211200

212201
return Mesh.from_vertices_and_faces(mapped_vertices, mapped_faces)

src/mapping.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,29 @@ std::tuple<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor
184184
for (const auto &point_id : fixed_vertices){
185185
fixed.emplace_back(Clipper2Lib::PointD(flattned_target_uv(point_id, 0), flattned_target_uv(point_id, 1)));
186186
}
187-
187+
188+
////////////////////////////////////////////////////////////////////////////////////////
189+
// Check and correct polygon orientations to ensure they're all counter-clockwise
190+
////////////////////////////////////////////////////////////////////////////////////////
191+
std::vector<std::vector<int>> corrected_pattern_f = pattern_f;
192+
193+
// Function to check if a polygon is counter-clockwise oriented
194+
auto is_counter_clockwise = [&pattern_v](const std::vector<int>& face_indices) -> bool {
195+
double sum = 0.0;
196+
for (size_t i = 0; i < face_indices.size(); i++) {
197+
sum += (pattern_v(face_indices[(i + 1) % face_indices.size()], 0) - pattern_v(face_indices[i], 0)) *
198+
(pattern_v(face_indices[(i + 1) % face_indices.size()], 1) + pattern_v(face_indices[i], 1));
199+
}
200+
return sum < 0;
201+
};
202+
203+
// Check and correct orientations of all input polygon faces
204+
for (size_t i = 0; i < corrected_pattern_f.size(); i++) {
205+
if (!is_counter_clockwise(corrected_pattern_f[i])) {
206+
std::reverse(corrected_pattern_f[i].begin(), corrected_pattern_f[i].end());
207+
}
208+
}
209+
188210
////////////////////////////////////////////////////////////////////////////////////////
189211
// Get Boundary polygon of a Mesh as Clipper Path.
190212
////////////////////////////////////////////////////////////////////////////////////////
@@ -215,7 +237,7 @@ std::tuple<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor
215237
std::vector<Clipper2Lib::PathsD> patterns_to_cut;
216238
std::vector<Clipper2Lib::PathsD> patterns_to_keep;
217239

218-
for (const auto &polyline_ids : pattern_f)
240+
for (const auto &polyline_ids : corrected_pattern_f)
219241
{
220242

221243
// Convert to clipper paths
@@ -422,6 +444,7 @@ std::tuple<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor
422444
int idx = find_or_add_point(point.x, point.y);
423445
face.push_back(idx);
424446
}
447+
425448
faces.push_back(face);
426449
groups.push_back(group_id);
427450
is_boundary.push_back(false);

0 commit comments

Comments
 (0)