Skip to content

Commit 0385457

Browse files
committed
Improving projection API to converge to MeshDomain
1 parent bde9b9a commit 0385457

3 files changed

Lines changed: 156 additions & 31 deletions

File tree

Mesh_smoothing_3/doc/Mesh_smoothing_3/Concepts/C3t3Projector.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ using Curve_edge = `std::pair<Curve_index, Edge>`;
7272
/*!
7373
Return the plane the patch face should align to.
7474
*/
75-
`std::pair<Point_3, Vector_3>` patch_projection_plane(Patch_face patch_face, Point_3 face_center, double face_radius) const;
75+
std::pair<Point_3, Vector_3> patch_projection_plane(Patch_face patch_face, std::vector<Point_3> face_points) const;
7676

7777
/*!
7878
Return if a patch face should be projected or not.
@@ -83,7 +83,7 @@ bool project_patch_face(Patch_face patch_face) const;
8383
/*!
8484
Return the line the curve edge should align to.
8585
*/
86-
std::pair<Point_3, Vector_3> curve_projection_tangent(Curve_edge curve_edge, Point_3 edge_center, double segment_size) const;
86+
std::pair<Point_3, Vector_3> curve_projection_tangent(Curve_edge curve_edge, std::array<Point_3,2> edge_points) const;
8787

8888
/*!
8989
Return if a curve edge should be projected or not.

Mesh_smoothing_3/include/CGAL/Mesh_smoothing_3/boundary_aware_mesh_smoothing.h

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <CGAL/AABB_tree.h>
2222
#include <CGAL/AABB_traits_3.h>
2323
#include <CGAL/AABB_primitive.h>
24+
#include <CGAL/centroid.h>
2425

2526
#include <map>
2627
#include <vector>
@@ -121,6 +122,16 @@ get(const Edge_to_point_property_map<C3t3>&, const typename C3t3::Edge& e)
121122
} // namespace internal
122123

123124

125+
126+
template <typename Point3,
127+
typename Vector3>
128+
struct Projection_data {
129+
Point3 origin = Point3();
130+
Vector3 vector = Vector3();
131+
bool activated = true;
132+
double weight = 1.;
133+
};
134+
124135
/*!
125136
* \ingroup pkgMeshSmoothing3Projection
126137
*
@@ -143,36 +154,39 @@ class C3t3_mesh_projector {
143154
public:
144155
using Point_3 = typename K::Point_3;
145156
using Vector_3 = typename K::Vector_3;
157+
using Projection = Projection_data<Point_3, Vector_3>;
146158

147159
using Surface_patch_index = typename C3t3::Surface_patch_index;
148160
using Facet = typename C3t3::Facet;
149161
using Patch_face = std::pair<Surface_patch_index, Facet>;
150162

151-
std::pair<Point_3, Vector_3> patch_projection_plane(Patch_face patch_face, Point_3 face_center, double /*face_radius*/) const {
163+
Projection patch_projection_plane(Patch_face patch_face, std::vector<Point_3> const &face_points) const {
164+
Projection projection;
165+
Point_3 face_center = CGAL::centroid(face_points.begin(), face_points.end());
152166
auto res = _facet_trees.at(patch_face.first).closest_point_and_primitive(face_center);
153-
Point_3 closest_point = res.first;
167+
projection.origin = res.first;
154168
const auto triangle = _c3t3->triangulation().triangle(res.second);
155-
Vector_3 normal = CGAL::unit_normal(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2));
156-
return {closest_point, normal};
169+
projection.vector = CGAL::unit_normal(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2));
170+
return projection;
157171
}
158-
bool project_patch_face(Patch_face) const { return true; }
159172

160173
using Curve_index = typename C3t3::Curve_index;
161174
using Edge = typename C3t3::Edge;
162175
using Curve_edge = std::pair<Curve_index, Edge>;
163176

164-
std::pair<Point_3, Vector_3> curve_projection_tangent(Curve_edge curve_edge, Point_3 edge_center, double /*segment_size*/) const {
177+
Projection curve_projection_tangent(Curve_edge curve_edge, std::array<Point_3,2> const &edge_points) const {
178+
Projection projection;
179+
Point_3 edge_center = CGAL::midpoint(edge_points[0], edge_points[1]);
165180
auto res = _edge_trees.at(curve_edge.first).closest_point_and_primitive(edge_center);
166-
Point_3 closest_point = res.first;
181+
projection.origin = res.first;
167182
const auto segment = _c3t3->triangulation().segment(res.second);
168-
Vector_3 direction = (segment.target() - segment.source());
169-
if (direction.squared_length() > 1e-8) {
170-
direction /= CGAL::sqrt(direction.squared_length());
183+
projection.vector = (segment.target() - segment.source());
184+
if (projection.vector.squared_length() > 1e-8) {
185+
projection.vector /= CGAL::sqrt(projection.vector.squared_length());
171186
}
172-
return {closest_point, direction};
187+
return projection;
173188
}
174189

175-
bool project_curve_edge(Curve_edge) const { return true; }
176190

177191
public:
178192

@@ -264,26 +278,82 @@ class C3t3_no_projection {
264278
public:
265279
using Point_3 = typename K::Point_3;
266280
using Vector_3 = typename K::Vector_3;
281+
using Projection = Projection_data<Point_3, Vector_3>;
267282

268283
using Surface_patch_index = typename C3t3::Surface_patch_index;
269284
using Facet = typename C3t3::Facet;
270285
using Patch_face = std::pair<Surface_patch_index, Facet>;
271286

272-
std::pair<Point_3, Vector_3> patch_projection_plane(Patch_face, Point_3, double) const {
273-
return {Point_3(), Vector_3()};
287+
Projection patch_projection_plane(Patch_face, std::vector<Point_3> const &) const {
288+
Point_3 face_center = CGAL::centroid(face_points.begin(), face_points.end());
289+
Vector_3 normal = CGAL::unit_normal(face_points[0], face_points[1], face_points[2]); // only works for triangles, but let's start with that
290+
Ray_3 ray_positive(face_center, normal);
291+
Ray_3 ray_negative(face_center, -normal);
292+
return Projection{Point_3(), Vector_3(), false};
274293
}
275-
bool project_patch_face(Patch_face) const { return false; }
276294

277295
using Curve_index = typename C3t3::Curve_index;
278296
using Edge = typename C3t3::Edge;
279297
using Curve_edge = std::pair<Curve_index, Edge>;
280298

281-
std::pair<Point_3, Vector_3> curve_projection_tangent(Curve_edge, Point_3, double) const {
282-
return {Point_3(), Vector_3()};
299+
Projection curve_projection_tangent(Curve_edge, std::array<Point_3,2> const &) const {
300+
return Projection{Point_3(), Vector_3(), false};
283301
}
284-
bool project_curve_edge(Curve_edge) const { return false; }
285302

286303
};
304+
305+
306+
/*
307+
* \ingroup pkgMeshSmoothing3Projection
308+
*
309+
* \brief provides projection to a Mesh Domain
310+
*
311+
* @tparam C3t3 model of `MeshDomain_3`
312+
*
313+
* \cgalModels{C3t3Projector}
314+
*
315+
\sa `CGAL::boundary_aware_mesh_smoothing`
316+
*
317+
*/
318+
template<typename C3t3, typename MeshDomain>
319+
class Mesh_domain_projection {
320+
using K = typename C3t3::Triangulation::Geom_traits;
321+
public:
322+
using Point_3 = typename K::Point_3;
323+
using Vector_3 = typename K::Vector_3;
324+
using Projection = Projection_data<Point_3, Vector_3>;
325+
326+
using Surface_patch_index = typename C3t3::Surface_patch_index;
327+
using Facet = typename C3t3::Facet;
328+
using Patch_face = std::pair<Surface_patch_index, Facet>;
329+
330+
Projection patch_projection_plane(Patch_face, std::vector<Point_3> const &) const {
331+
return Projection();
332+
}
333+
334+
using Curve_index = typename C3t3::Curve_index;
335+
using Edge = typename C3t3::Edge;
336+
using Curve_edge = std::pair<Curve_index, Edge>;
337+
338+
Projection curve_projection_tangent(Curve_edge, std::array<Point_3,2> const &) const {
339+
return Projection();
340+
}
341+
342+
public:
343+
344+
/*
345+
Class constructor
346+
347+
\param mesh_domain contains the domain used for projection
348+
349+
*/
350+
Mesh_domain_projection(MeshDomain const& mesh_domain)
351+
: _domain(mesh_domain)
352+
{}
353+
354+
MeshDomain const& _domain;
355+
};
356+
287357
} // namespace Mesh_smoothing_3
288358

289359
/*!
@@ -415,16 +485,16 @@ void boundary_aware_mesh_smoothing (
415485
using Vector_3 = typename C3t3::Triangulation::Geom_traits::Vector_3;
416486

417487
// converting Projector to Mesh_smoothing_3 queries
418-
smoother.set_boundary_query([&](const Point_3& pt, std::pair<typename C3t3::Surface_patch_index, typename C3t3::Facet> patch_face, double radius) {
419-
if (!projector.project_patch_face(patch_face)) return std::make_tuple(Point_3(0.,0.,0.), Vector_3{1.,0.,0.}, 0.);
420-
auto [point, normal] = projector.patch_projection_plane(patch_face, pt, radius);
421-
return std::make_tuple(point, normal, 1.0);
488+
smoother.set_boundary_query([&](std::vector<Point_3> const& pts, std::pair<typename C3t3::Surface_patch_index, typename C3t3::Facet> patch_face) {
489+
Mesh_smoothing_3::Projection_data<Point_3, Vector_3> proj = projector.patch_projection_plane(patch_face, pts);
490+
if (!proj.activated) proj.weight = 0.;
491+
return std::make_tuple(proj.origin, proj.vector, proj.weight);
422492
});
423493

424-
smoother.set_curves_query([&](const Point_3& pt, std::pair<typename C3t3::Curve_index, typename C3t3::Edge> curve_edge, double segment_size) {
425-
if (!projector.project_curve_edge(curve_edge)) return std::make_tuple(Point_3(0.,0.,0.), Vector_3{1.,0.,0.}, 0.);
426-
auto [point, tangent] = projector.curve_projection_tangent(curve_edge, pt, segment_size);
427-
return std::make_tuple(point, tangent, 1.0);
494+
smoother.set_curves_query([&](std::array<Point_3, 2> const& pts, std::pair<typename C3t3::Curve_index, typename C3t3::Edge> curve_edge) {
495+
Mesh_smoothing_3::Projection_data<Point_3, Vector_3> proj = projector.curve_projection_tangent(curve_edge, pts);
496+
if (!proj.activated) proj.weight = 0.;
497+
return std::make_tuple(proj.origin, proj.vector, proj.weight);
428498
});
429499

430500
smoother.set_verbose(verbose);

Mesh_smoothing_3/include/CGAL/Mesh_smoothing_3/internal/Mesh_smoothing_3_impl.h

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ void Mesh_smoother<TetrahedralMesh, BoundaryMesh, EdgeNetwork>::create_compress_
272272
}
273273
return (*res.first).second;
274274
};
275+
276+
// initialize volume
277+
275278
_tetrahedra.reserve(_mesh.nb_cells());
276279
_tetrahedron_refs.reserve(_mesh.nb_cells());
277280
for (auto cell : _mesh.cell_range()) {
@@ -300,7 +303,6 @@ void Mesh_smoother<TetrahedralMesh, BoundaryMesh, EdgeNetwork>::create_compress_
300303

301304
_tetrahedra.shrink_to_fit();
302305
_tetrahedron_refs.shrink_to_fit();
303-
_compressed_coords = Eigen::Map<Eigen::VectorXd>(temp_coordinates_storage.data(), static_cast<Eigen::Index>(temp_coordinates_storage.size()));
304306

305307
// computing vertex -> tet data structure
306308
std::vector<unsigned> curr_id(nb_points,0);
@@ -314,8 +316,61 @@ void Mesh_smoother<TetrahedralMesh, BoundaryMesh, EdgeNetwork>::create_compress_
314316
_vert2tet_corner[v][curr_id[v]++] = 4*t+i;
315317
}
316318
}
317-
initialize_boundary();
318-
initialize_curve_network();
319+
320+
// initialize boundary
321+
322+
std::vector<unsigned> currFace(10);
323+
_bnd_faces.reserve(_boundary.nb_faces());
324+
_face_surface_id.reserve(_boundary.nb_faces());
325+
std::unordered_map<unsigned, std::vector<std::array<unsigned, 2>>> vert2faces; // todo: maybe use a map from boost
326+
for (auto face : _boundary.face_range()) {
327+
bool hasUnlocked = false;
328+
for (auto vertex_descriptor : _boundary.face_vertices(face)) {
329+
if (!is_vert_locked(vertex_descriptor)) {
330+
hasUnlocked = true;
331+
break;
332+
}
333+
}
334+
if (!hasUnlocked) continue;
335+
currFace.clear();
336+
for (auto vertex_descriptor : _boundary.face_vertices(face)) {
337+
currFace.push_back(get_compressed_point_id(vertex_descriptor));
338+
}
339+
for (unsigned i = 0; i < currFace.size(); ++i) {
340+
if (_lock_boundary) {
341+
for (unsigned d = 0; d < 3; ++d) {
342+
_compressed_locks[3*currFace[i]+d] = true;
343+
}
344+
}
345+
std::array<unsigned, 2> location_pair = {static_cast<unsigned>(_bnd_faces.size()), i};
346+
auto res = vert2faces.emplace(currFace[i], std::vector<std::array<unsigned, 2>>{location_pair});
347+
if (!res.second) (*res.first).second.push_back(location_pair);
348+
}
349+
_bnd_faces.push_back(currFace);
350+
_face_surface_id.push_back(_boundary.patch_id(face));
351+
}
352+
// not ordered, do a sort? then I lose memory alignment? check if becomes bottleneck
353+
_vert_and_face_corners.assign(vert2faces.begin(), vert2faces.end());
354+
355+
356+
// initialize curve network
357+
358+
_curve_edges.reserve(_edge_network.nb_edges());
359+
_curve_ids.reserve(_edge_network.nb_edges());
360+
for (auto edge : _edge_network.edge_range()) {
361+
Vertex_descriptor v0 = _edge_network.edge_vertex(edge, 0);
362+
Vertex_descriptor v1 = _edge_network.edge_vertex(edge, 1);
363+
if (is_vert_locked(v0) && is_vert_locked(v1)) continue;
364+
_curve_edges.push_back({get_compressed_point_id(v0), get_compressed_point_id(v1)});
365+
_curve_ids.push_back(_edge_network.curve_id(edge));
366+
}
367+
368+
369+
370+
// initialize rest of data
371+
_point_targets.reserve(_vertex_target_positions.size());
372+
373+
_compressed_coords = Eigen::Map<Eigen::VectorXd>(temp_coordinates_storage.data(), static_cast<Eigen::Index>(temp_coordinates_storage.size()));
319374

320375
if (_update_validator != nullptr) {
321376
_current_coords_to_check.reserve(_mesh.nb_vertices());

0 commit comments

Comments
 (0)