@@ -63,37 +63,117 @@ pmp_remesh(
6363}
6464
6565std::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}
0 commit comments