Skip to content

Commit 175007e

Browse files
author
pv
committed
CHANGE separate meshing from dual.
1 parent b43d06f commit 175007e

File tree

4 files changed

+126
-47
lines changed

4 files changed

+126
-47
lines changed

docs/examples/example_meshing.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010
from compas.geometry import transform_points_numpy
1111
from compas_viewer import Viewer
1212

13-
from compas_cgal.meshing import mesh_remesh, mesh_remesh_dual
13+
from compas_cgal.meshing import mesh_remesh, mesh_dual
1414
from compas_cgal import _types_std # noqa: F401
1515

1616
def main():
1717
"""Remesh a bunny mesh that is loaded from .ply file."""
1818

1919
FILE = Path(__file__).parent.parent.parent / "data" / "Bunny.ply"
2020

21-
bunny = Mesh.from_ply(FILE)
22-
#bunny = Mesh.from_meshgrid(1,10,1,10)
21+
#bunny = Mesh.from_ply(FILE)
22+
bunny = Mesh.from_meshgrid(1,10,1,10)
2323
bunny.quads_to_triangles()
2424
bunny.remove_unused_vertices()
2525

@@ -36,16 +36,17 @@ def main():
3636
V1 = transform_points_numpy(V0, R * S * T)
3737

3838

39-
edge_length = 0.005
39+
edge_length = 0.3
4040
iterations = 10
41+
x_translation = 0.0
4142
V1, F1 = mesh_remesh((V0, F0), edge_length, iterations)
42-
V1 = transform_points_numpy(V1, Translation.from_vector([0.15, 0, 0]))
43+
V1 = transform_points_numpy(V1, Translation.from_vector([x_translation, 0, 0]))
4344
mesh = Mesh.from_vertices_and_faces(V1, F1)
4445

4546

46-
V1, F1 = mesh_remesh_dual((V0, F0), edge_length, iterations, 3.14, True)
47-
V1 = transform_points_numpy(V1, Translation.from_vector([0.3, 0, 0]))
48-
dual = Mesh.from_vertices_and_faces(V1, F1)
47+
V2, F2 = mesh_dual((V1, F1), 2.14, True)
48+
V2 = transform_points_numpy(V2, Translation.from_vector([x_translation, 0, 0]))
49+
dual = Mesh.from_vertices_and_faces(V2, F2)
4950

5051
return bunny, mesh, dual
5152

@@ -62,7 +63,7 @@ def main():
6263
viewer.renderer.camera.target = [0, 0, 0]
6364
viewer.renderer.camera.position = [0, -0.25, 0.10]
6465

65-
viewer.scene.add(bunny, show_points=False)
66+
# viewer.scene.add(bunny, show_points=False)
6667
viewer.scene.add(mesh, show_points=False)
6768
viewer.scene.add(dual, show_points=True)
6869

src/compas_cgal/meshing.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,30 +51,27 @@ def mesh_remesh(
5151
V, F = mesh
5252
V = np.asarray(V, dtype=np.float64, order="C")
5353
F = np.asarray(F, dtype=np.int32, order="C")
54-
return _meshing.remesh(V, F, target_edge_length, number_of_iterations)
54+
return _meshing.remesh(V, F, target_edge_length, number_of_iterations, do_project)
5555

5656

57-
def mesh_remesh_dual(
57+
def mesh_dual(
5858
mesh: VerticesFaces,
59-
target_edge_length: float,
60-
number_of_iterations: int = 10,
6159
angle_radians: float = 0.0,
6260
circumcenter: bool = True,
61+
scale_factor: float = 1.0,
6362
) -> tuple[np.ndarray, list[list[int]]]:
6463
"""Create a dual mesh from a triangular mesh with variable-length faces.
6564
6665
Parameters
6766
----------
6867
mesh : :attr:`compas_cgal.types.VerticesFaces`
6968
The mesh to create a dual from.
70-
target_edge_length : float
71-
The target edge length for primal mesh remeshing before dual creation.
72-
number_of_iterations : int, optional
73-
Number of remeshing iterations for the primal mesh.
7469
angle_radians : double, optional
7570
Angle limit in radians for boundary vertices to remove.
7671
circumcenter : bool, optional
7772
Whether to use the circumcenter of the triangle instead of the centroid.
73+
scale_factor : double, optional
74+
Scale factor for inner vertices.
7875
7976
Returns
8077
-------
@@ -110,5 +107,5 @@ def mesh_remesh_dual(
110107
V, F = mesh
111108
V = np.asarray(V, dtype=np.float64, order="C")
112109
F = np.asarray(F, dtype=np.int32, order="C")
113-
vertices, var_faces = _meshing.remesh_dual(V, F, target_edge_length, number_of_iterations, angle_radians, circumcenter)
110+
vertices, var_faces = _meshing.dual(V, F, angle_radians, circumcenter, scale_factor)
114111
return vertices, var_faces

src/meshing.cpp

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,37 +63,117 @@ pmp_remesh(
6363
}
6464

6565
std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>>
66-
pmp_remesh_dual(
66+
pmp_dual(
6767
Eigen::Ref<compas::RowMatrixXd> vertices_a,
6868
Eigen::Ref<compas::RowMatrixXi> faces_a,
69-
double target_edge_length,
70-
unsigned int number_of_iterations,
7169
double angle_radians,
72-
bool circumcenter)
70+
bool circumcenter,
71+
double scale_factor)
7372
{
73+
7474
/////////////////////////////////////////////////////////////////////////////////
75-
// Initial Mesh Preparation
75+
// Mesh Creation
7676
/////////////////////////////////////////////////////////////////////////////////
77-
// This section initializes the primal mesh and performs remeshing to create
78-
// a high-quality input for dual mesh generation. The mesh is cleaned up
79-
// to ensure a consistent structure without any stray elements.
80-
81-
compas::Mesh mesh_a = compas::mesh_from_vertices_and_faces(vertices_a, faces_a); // Convert input matrices to CGAL mesh
82-
CGAL::Polygon_mesh_processing::isotropic_remeshing(
83-
faces(mesh_a),
84-
target_edge_length,
85-
mesh_a,
86-
CGAL::Polygon_mesh_processing::parameters::number_of_iterations(number_of_iterations)
87-
.do_project(true));
88-
mesh_a.collect_garbage(); // Clean up the mesh
77+
compas::Mesh mesh_a = compas::mesh_from_vertices_and_faces(vertices_a, faces_a);
78+
79+
80+
/////////////////////////////////////////////////////////////////////////////////
81+
// Scalled inner vertices
82+
/////////////////////////////////////////////////////////////////////////////////
83+
84+
if (scale_factor != 1.0 && scale_factor > 0.0){
85+
// Make a copy of the original mesh before scaling
86+
compas::Mesh original_mesh = mesh_a;
87+
88+
// Calculate mesh centroid first
89+
CGAL::Point_3<compas::Kernel> centroid(0, 0, 0);
90+
int vertex_count = 0;
91+
for(auto v : vertices(mesh_a)) {
92+
centroid = centroid + (mesh_a.point(v) - CGAL::ORIGIN);
93+
vertex_count++;
94+
}
95+
centroid = CGAL::ORIGIN + (centroid - CGAL::ORIGIN) / vertex_count;
96+
97+
// Scale inner vertices relative to centroid
98+
for(auto v : vertices(mesh_a)) {
99+
// Check if the vertex is on the boundary
100+
bool is_boundary = false;
101+
for(auto h : CGAL::halfedges_around_target(v, mesh_a)) {
102+
if(is_border(h, mesh_a)) {
103+
is_boundary = true;
104+
break;
105+
}
106+
}
107+
108+
// Only scale inner vertices
109+
if(!is_boundary) {
110+
auto p = mesh_a.point(v);
111+
// Calculate vector from centroid to point, scale it, then set the new position
112+
CGAL::Vector_3<compas::Kernel> vec(centroid, p);
113+
vec = vec * scale_factor;
114+
mesh_a.point(v) = centroid + vec;
115+
}
116+
}
117+
118+
// After scaling, use proper AABB tree for projection
119+
// Define triangle type
120+
typedef CGAL::Kernel_traits<CGAL::Point_3<compas::Kernel>>::Kernel K;
121+
typedef CGAL::Triangle_3<K> Triangle;
122+
typedef std::vector<Triangle>::iterator Iterator;
123+
124+
// Build a list of triangles from the original mesh
125+
std::vector<Triangle> triangles;
126+
for(auto face : faces(original_mesh)) {
127+
auto halfedge = original_mesh.halfedge(face);
128+
auto v0 = original_mesh.source(halfedge);
129+
auto v1 = original_mesh.target(halfedge);
130+
auto v2 = original_mesh.target(next(halfedge, original_mesh));
131+
132+
// Add the triangle
133+
triangles.push_back(Triangle(
134+
original_mesh.point(v0),
135+
original_mesh.point(v1),
136+
original_mesh.point(v2)
137+
));
138+
}
139+
140+
// Create the AABB tree
141+
typedef CGAL::AABB_triangle_primitive_3<K, Iterator> Primitive;
142+
typedef CGAL::AABB_traits_3<K, Primitive> Traits;
143+
typedef CGAL::AABB_tree<Traits> Tree;
144+
145+
Tree tree(triangles.begin(), triangles.end());
146+
tree.accelerate_distance_queries();
147+
148+
// Project each inner vertex to closest point on original mesh
149+
for(auto v : vertices(mesh_a)) {
150+
bool is_boundary = false;
151+
for(auto h : CGAL::halfedges_around_target(v, mesh_a)) {
152+
if(is_border(h, mesh_a)) {
153+
is_boundary = true;
154+
break;
155+
}
156+
}
157+
158+
if(!is_boundary) {
159+
auto p = mesh_a.point(v);
160+
auto closest = tree.closest_point(p);
161+
mesh_a.point(v) = closest;
162+
}
163+
}
89164

165+
166+
}
167+
90168
/////////////////////////////////////////////////////////////////////////////////
91169
// Dual Graph Creation
92170
/////////////////////////////////////////////////////////////////////////////////
93171
// Create the dual graph structure and a filtered version that excludes border
94172
// elements. This filtered graph will be used to generate the interior portion
95173
// of the dual mesh.
96174

175+
176+
97177
typedef CGAL::Dual<compas::Mesh> DualMesh;
98178
DualMesh dual(mesh_a);
99179

@@ -452,14 +532,13 @@ NB_MODULE(_meshing, m) {
452532
);
453533

454534
m.def(
455-
"remesh_dual",
456-
&pmp_remesh_dual,
535+
"dual",
536+
&pmp_dual,
457537
"Create a dual mesh from a triangular mesh",
458538
"vertices_a"_a,
459539
"faces_a"_a,
460-
"target_edge_length"_a,
461-
"number_of_iterations"_a = 10,
462540
"angle_radians"_a = 0.5,
463-
"circumcenter"_a = true
541+
"circumcenter"_a = true,
542+
"scale_factor"_a = 1.0
464543
);
465544
}

src/meshing.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#include <CGAL/Polygon_mesh_processing/remesh.h>
77
#include <CGAL/Polygon_mesh_processing/detect_features.h>
88
#include <CGAL/boost/graph/Dual.h>
9+
#include <CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h>
10+
#include <CGAL/AABB_tree.h>
11+
#include <CGAL/AABB_traits_3.h>
12+
#include <CGAL/AABB_triangle_primitive_3.h>
913

1014
namespace compas {
1115

@@ -67,19 +71,17 @@ pmp_remesh(
6771
*
6872
* @param vertices_a Matrix of vertex positions as Nx3 matrix in row-major order (float64)
6973
* @param faces_a Matrix of face indices as Mx3 matrix in row-major order (int32)
70-
* @param target_edge_length Desired length for mesh edges
71-
* @param number_of_iterations Number of remeshing iterations
7274
* @param angle_radians Angle limit in radians for boundary vertices
73-
* @param circumcenter Whether to use the circumcenter of the triangle instead of the centroid
75+
* @param circumcenter Whether to use the circumcenter of the triangle instead of the centroid.
76+
* @param scale_factor Scale factor for inner vertices.
7477
* @return std::tuple<RowMatrixXd, std::vector<std::vector<int>>> containing:
7578
* - New vertices as Rx3 matrix (float64)
7679
* - New faces as Sx3 matrix (int32)
7780
*/
7881
std::tuple<compas::RowMatrixXd, std::vector<std::vector<int>>>
79-
pmp_remesh_dual(
82+
pmp_dual(
8083
Eigen::Ref<compas::RowMatrixXd> vertices_a,
8184
Eigen::Ref<compas::RowMatrixXi> faces_a,
82-
double target_edge_length,
83-
unsigned int number_of_iterations = 10,
8485
double angle_radians = 0.5,
85-
bool circumcenter = true);
86+
bool circumcenter = true,
87+
double scale_factor = 1.0);

0 commit comments

Comments
 (0)