mirror of https://github.com/CGAL/cgal
Merge pull request #6021 from MaelRL/PMP-Snap_with_KD_tree-GF
Improvements for PMP's snapping code
This commit is contained in:
commit
bb58df3ae5
|
|
@ -37,7 +37,8 @@ void vertices_as_halfedges(const VertexRange& vertex_range,
|
|||
*out++ = halfedge(v, pmesh);
|
||||
}
|
||||
|
||||
// Assigns at each vertex the 'tolerance' value as tolerance, but bounded by a percentage of the length of its shortest incident edge
|
||||
// Assigns at each vertex the 'tolerance' value as tolerance,
|
||||
// but bounded by a percentage of the length of its shortest incident edge
|
||||
template <typename HalfedgeRange,
|
||||
typename ToleranceMap,
|
||||
typename PolygonMesh,
|
||||
|
|
@ -116,9 +117,14 @@ bool is_collinear_with_tolerance(const typename GeomTraits::Point_3& p, // va ==
|
|||
const FT sp = gt.compute_scalar_product_3_object()(va, vb);
|
||||
|
||||
// To avoid junctions like:
|
||||
// ----va vb----- from being locked since it could be needed in ------------- later
|
||||
// | | ----va vb---
|
||||
// | |
|
||||
// ----va vb-----
|
||||
// | |
|
||||
//
|
||||
// from being locked since it could be needed in a configuration such as
|
||||
// -------------
|
||||
// ----va vb---
|
||||
// | |
|
||||
// later
|
||||
if(sp < FT(0))
|
||||
return false;
|
||||
|
||||
|
|
@ -129,6 +135,119 @@ bool is_collinear_with_tolerance(const typename GeomTraits::Point_3& p, // va ==
|
|||
return (CGAL::square(sp) >= sq_va_l * sq_vb_l * sq_cos);
|
||||
}
|
||||
|
||||
template <typename PolygonMesh>
|
||||
struct Snapping_default_visitor
|
||||
{
|
||||
bool m_stop = false;
|
||||
|
||||
bool stop() { return m_stop; }
|
||||
|
||||
// ------------------------------- Preprocessing ------------------------------
|
||||
|
||||
// Called when starting preprocessing phase of the mesh.
|
||||
void start_mesh_preprocessing() { }
|
||||
|
||||
// Called at the end of the preprocessing phase of the mesh.
|
||||
void end_mesh_preprocessing() { }
|
||||
|
||||
// ------------------------------- Vertex - Vertex -------------------------------
|
||||
|
||||
// Called when starting snapping a range of vertices of `A` and a range of vertices of `B`.
|
||||
void start_vertex_vertex_phase() { }
|
||||
|
||||
// Called when finished snapping a range of vertices of `A` and a range of vertices of `B`.
|
||||
void end_vertex_vertex_phase() { }
|
||||
|
||||
// Called when trying to find `v`-`v_other` pair (with `v` in `A` and `v_other` in `B`)
|
||||
//
|
||||
// Available only if vertex-vertex pair detection is based on the kd-tree.
|
||||
// Must be threadsafe if parallelism is used.
|
||||
template <typename Vertex, typename Mesh>
|
||||
void on_vertex_vertex_inquiry(const Vertex /*v*/, const Mesh&) { }
|
||||
|
||||
// Called when a match between two ranges of vertices is found.
|
||||
// All vertices in `va` have the same position (and same for `vb`).
|
||||
//
|
||||
// Must be threadsafe if parallelism is used.
|
||||
template <typename VertexContainer, typename Mesh>
|
||||
void on_vertex_vertex_match(const VertexContainer& /*va*/, const Mesh&,
|
||||
const VertexContainer& /*vb*/, const Mesh&) { }
|
||||
|
||||
// Called before proceeding with actual vertex-vertex snapping.
|
||||
void start_vertex_vertex_snapping() { }
|
||||
|
||||
// Called after proceeding with actual vertex-vertex snapping.
|
||||
void end_vertex_vertex_snapping() { }
|
||||
|
||||
// Called before two ranges of vertices are snapped together.
|
||||
// All vertices in `va` have the same position (and same for `vb`).
|
||||
template <typename VertexContainer, typename Mesh>
|
||||
void before_vertex_vertex_snap(const VertexContainer& /*va*/, const Mesh&,
|
||||
const VertexContainer& /*vb*/, const Mesh&) { }
|
||||
|
||||
// Called after two ranges of vertices have been snapped.
|
||||
template <typename VertexContainer, typename Mesh>
|
||||
void after_vertex_vertex_snap(const VertexContainer& /*va*/, const Mesh&,
|
||||
const VertexContainer& /*vb*/, const Mesh&) { }
|
||||
|
||||
// ------------------------------- Vertex - Edge -------------------------------
|
||||
|
||||
// Called when starting snapping a range of vertices of A onto edges of B
|
||||
void start_first_vertex_edge_phase() { }
|
||||
|
||||
// Called when finished snapping a range of vertices of A onto edges of B
|
||||
void end_first_vertex_edge_phase() { }
|
||||
|
||||
// Called when starting snapping a range of vertices of B onto edges of A.
|
||||
// Not called if A and B are the same mesh.
|
||||
void start_second_vertex_edge_phase() { }
|
||||
|
||||
// Called when starting snapping a range of vertices of B onto edges of A.
|
||||
// Not called if A and B are the same mesh.
|
||||
void end_second_vertex_edge_phase() { }
|
||||
|
||||
// Called when trying to find `v`-`edge` pair
|
||||
//
|
||||
// Available only if vertex-vertex pair detection is based on the kd-tree.
|
||||
// Must be threadsafe if parallelism is used.
|
||||
template <typename Vertex, typename Mesh>
|
||||
void on_vertex_edge_inquiry(const Vertex /*v*/, const Mesh& /*tm*/) { }
|
||||
|
||||
// Called when a match between a vertex and an edge is found.
|
||||
//
|
||||
// Must be threadsafe if parallelism is used.
|
||||
template <typename Vertex, typename Edge, typename Mesh, typename Point>
|
||||
void on_vertex_edge_match(const Vertex, const Mesh&, const Edge, const Mesh&, const Point&) { }
|
||||
|
||||
// Called before proceeding with actual snapping.
|
||||
void start_vertex_edge_snapping() { }
|
||||
|
||||
// Called after proceeding with actual snapping.
|
||||
void end_vertex_edge_snapping() { }
|
||||
|
||||
// Called before a new vertex is created.
|
||||
template <typename Edge, typename Mesh, typename Point>
|
||||
void before_vertex_edge_snap(const Edge, const Mesh&, const Point&) { }
|
||||
|
||||
// Called after a new vertex has been created, splitting an edge.
|
||||
template <typename Vertex, typename Mesh>
|
||||
void after_vertex_edge_snap(const Vertex /*new_vertex*/, const Mesh&) { }
|
||||
|
||||
// ------------------------------- Two passes (segmentation or not) ------------------------------
|
||||
|
||||
// Called at the start of the snapping pass that is restricted to compatible patch (first pass).
|
||||
void start_patch_snapping() { }
|
||||
|
||||
// Called at the end of the snapping pass that is restricted to compatible patch (first pass).
|
||||
void end_patch_snapping() { }
|
||||
|
||||
// Called at the start of the second snapping pass, all elements are potentially compatible (second pass).
|
||||
void start_global_snapping() { }
|
||||
|
||||
// Called at the end of the second snapping pass, all elements are potentially compatible (second pass).
|
||||
void end_global_snapping() { }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Polygon_mesh_processing
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ void simplify_range(HalfedgeRange& halfedge_range,
|
|||
typedef typename GT::FT FT;
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::type VPM;
|
||||
typedef typename boost::property_traits<VPM>::value_type Point;
|
||||
typedef typename boost::property_traits<VPM>::reference Point_ref;
|
||||
|
||||
using parameters::get_parameter;
|
||||
|
|
@ -125,10 +126,10 @@ void simplify_range(HalfedgeRange& halfedge_range,
|
|||
// @fixme what if the source vertex is not to be snapped? Tolerance cannot be obtained...
|
||||
// and where should the post-collapse vertex be since we can't move the source vertex...
|
||||
// --> simply don't collapse?
|
||||
const FT min_tol = (std::min)(get(tolerance_map, vs), get(tolerance_map, vt));
|
||||
const FT max_tol = (std::max)(get(tolerance_map, vs), get(tolerance_map, vt));
|
||||
const FT tol_s = get(tolerance_map, vs), tol_t = get(tolerance_map, vt);
|
||||
const FT max_tol = (std::max)(tol_s, tol_t);
|
||||
|
||||
if(gt.compare_squared_distance_3_object()(ps,pt,CGAL::square(max_tol))==SMALLER)
|
||||
if(gt.compare_squared_distance_3_object()(ps,pt,CGAL::square(max_tol)) == SMALLER)
|
||||
{
|
||||
const halfedge_descriptor prev_h = prev(h, tm);
|
||||
const halfedge_descriptor next_h = next(h, tm);
|
||||
|
|
@ -136,11 +137,23 @@ void simplify_range(HalfedgeRange& halfedge_range,
|
|||
// check that the border has at least 4 edges not to create degenerate volumes
|
||||
if(border_size(h, tm) >= 4)
|
||||
{
|
||||
const FT h_sq_length = gt.compute_squared_distance_3_object()(ps, pt);
|
||||
vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm);
|
||||
const FT lambda = tol_s / (tol_s + tol_t);
|
||||
const Point new_p = ps + lambda * (pt - ps);
|
||||
|
||||
put(vpm, v, gt.construct_midpoint_3_object()(ps, pt));
|
||||
put(tolerance_map, v, min_tol + 0.5 * CGAL::approximate_sqrt(h_sq_length));
|
||||
// If we're collapsing onto a vertex that is not allowed to move, keep it fixed
|
||||
const FT min_tol = (std::min)(tol_s, tol_t);
|
||||
FT new_tolerance = min_tol;
|
||||
if(!is_zero(min_tol))
|
||||
{
|
||||
if(tol_t > tol_s) // the new point is closer to ps than to pt
|
||||
new_tolerance += CGAL::approximate_sqrt(CGAL::squared_distance(new_p, ps));
|
||||
else
|
||||
new_tolerance += CGAL::approximate_sqrt(CGAL::squared_distance(new_p, pt));
|
||||
}
|
||||
|
||||
vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm);
|
||||
put(vpm, v, new_p);
|
||||
put(tolerance_map, v, new_tolerance);
|
||||
|
||||
if(get(range_halfedges, prev_h))
|
||||
edges_to_test.insert(prev_h);
|
||||
|
|
@ -453,7 +466,8 @@ template <typename ConcurrencyTag = CGAL::Sequential_tag,
|
|||
typename VertexWithTolerance, typename TriangleMesh,
|
||||
typename EdgeToSplitMap, typename AABBTree,
|
||||
typename VertexPatchMap_S, typename FacePatchMap_T,
|
||||
typename VPMS, typename VPMT, typename GT>
|
||||
typename VPMS, typename VPMT, typename GT,
|
||||
typename Visitor>
|
||||
void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
||||
EdgeToSplitMap& edges_to_split,
|
||||
const AABBTree* aabb_tree_ptr,
|
||||
|
|
@ -463,7 +477,8 @@ void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
|||
const TriangleMesh& tm_T,
|
||||
FacePatchMap_T face_patch_map_T,
|
||||
VPMT vpm_T,
|
||||
const GT& gt)
|
||||
const GT& gt,
|
||||
Visitor& visitor)
|
||||
{
|
||||
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
|
@ -477,6 +492,9 @@ void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
|||
|
||||
typedef internal::Projection_traits<TriangleMesh, VPMS, VPMT, FacePatchMap_T, AABB_traits> Projection_traits;
|
||||
|
||||
if(visitor.stop())
|
||||
throw CGAL::internal::Throw_at_output_exception();
|
||||
|
||||
// by construction the whole range has the same position
|
||||
const halfedge_descriptor h = vertex_with_tolerance.first;
|
||||
const vertex_descriptor v = target(h, tm_S);
|
||||
|
|
@ -488,6 +506,8 @@ void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
|||
std::cout << "--------------------------- Query: " << v << " (" << query << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
visitor.on_vertex_edge_inquiry(v, tm_S);
|
||||
|
||||
Projection_traits traversal_traits(h, patch_id, sq_tolerance, tm_S, vpm_S,
|
||||
tm_T, face_patch_map_T, vpm_T, aabb_tree_ptr->traits());
|
||||
aabb_tree_ptr->traversal(query, traversal_traits);
|
||||
|
|
@ -522,7 +542,6 @@ void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
|||
if(!is_close_enough)
|
||||
return;
|
||||
|
||||
|
||||
CGAL_assertion(get(vpm_T, source(closest_e, tm_T)) != query &&
|
||||
get(vpm_T, target(closest_e, tm_T)) != query);
|
||||
|
||||
|
|
@ -534,43 +553,17 @@ void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance,
|
|||
|
||||
// Using a map because we need to know if the same halfedge is split multiple times
|
||||
Edges_to_split_map_inserter<ConcurrencyTag>()(edges_to_split, closest_h, vertex_with_tolerance.first, closest_p);
|
||||
|
||||
visitor.on_vertex_edge_match(v, tm_S, closest_h, tm_T, closest_p);
|
||||
}
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
template <typename PointWithToleranceContainer,
|
||||
typename TriangleMesh, typename EdgeToSplitMap, typename AABBTree,
|
||||
typename VertexPatchMap_S, typename FacePatchMap_T,
|
||||
typename VPMS, typename VPMT, typename GT>
|
||||
struct Find_splittable_edge_for_parallel_for
|
||||
typename VPMS, typename VPMT, typename GT, typename Visitor>
|
||||
struct Parallel_find_splittable_edge
|
||||
{
|
||||
Find_splittable_edge_for_parallel_for(const PointWithToleranceContainer& points_with_tolerance,
|
||||
EdgeToSplitMap& edges_to_split,
|
||||
const AABBTree* aabb_tree_ptr,
|
||||
const TriangleMesh& tm_S,
|
||||
const VertexPatchMap_S vertex_patch_map_S,
|
||||
const VPMS vpm_S,
|
||||
const TriangleMesh& tm_T,
|
||||
const FacePatchMap_T face_patch_map_T,
|
||||
const VPMT vpm_T,
|
||||
const GT& gt)
|
||||
:
|
||||
m_points_with_tolerance(points_with_tolerance),
|
||||
m_edges_to_split(edges_to_split), m_aabb_tree_ptr(aabb_tree_ptr),
|
||||
m_tm_S(tm_S), m_vertex_patch_map_S(vertex_patch_map_S), m_vpm_S(vpm_S),
|
||||
m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T),
|
||||
m_gt(gt)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<size_t>& r) const
|
||||
{
|
||||
for(std::size_t i=r.begin(); i!=r.end(); ++i)
|
||||
{
|
||||
find_splittable_edge<CGAL::Parallel_tag>(m_points_with_tolerance[i], m_edges_to_split, m_aabb_tree_ptr,
|
||||
m_tm_S, m_vertex_patch_map_S, m_vpm_S,
|
||||
m_tm_T, m_face_patch_map_T, m_vpm_T, m_gt);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const PointWithToleranceContainer& m_points_with_tolerance;
|
||||
EdgeToSplitMap& m_edges_to_split;
|
||||
|
|
@ -582,18 +575,51 @@ private:
|
|||
const FacePatchMap_T m_face_patch_map_T;
|
||||
const VPMT m_vpm_T;
|
||||
const GT& m_gt;
|
||||
Visitor& m_visitor;
|
||||
|
||||
public:
|
||||
Parallel_find_splittable_edge(const PointWithToleranceContainer& points_with_tolerance,
|
||||
EdgeToSplitMap& edges_to_split,
|
||||
const AABBTree* aabb_tree_ptr,
|
||||
const TriangleMesh& tm_S,
|
||||
const VertexPatchMap_S vertex_patch_map_S,
|
||||
const VPMS vpm_S,
|
||||
const TriangleMesh& tm_T,
|
||||
const FacePatchMap_T face_patch_map_T,
|
||||
const VPMT vpm_T,
|
||||
const GT& gt,
|
||||
Visitor& visitor)
|
||||
:
|
||||
m_points_with_tolerance(points_with_tolerance),
|
||||
m_edges_to_split(edges_to_split), m_aabb_tree_ptr(aabb_tree_ptr),
|
||||
m_tm_S(tm_S), m_vertex_patch_map_S(vertex_patch_map_S), m_vpm_S(vpm_S),
|
||||
m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T),
|
||||
m_gt(gt), m_visitor(visitor)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<size_t>& r) const
|
||||
{
|
||||
for(std::size_t i=r.begin(); i!=r.end(); ++i)
|
||||
{
|
||||
find_splittable_edge<CGAL::Parallel_tag>(m_points_with_tolerance[i], m_edges_to_split, m_aabb_tree_ptr,
|
||||
m_tm_S, m_vertex_patch_map_S, m_vpm_S,
|
||||
m_tm_T, m_face_patch_map_T, m_vpm_T, m_gt, m_visitor);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename EdgesToSplitContainer,
|
||||
typename TriangleMesh, typename GeomTraits,
|
||||
typename VPMS, typename VPMT>
|
||||
typename TriangleMesh,
|
||||
typename VPMS, typename VPMT, typename GeomTraits,
|
||||
typename Visitor>
|
||||
std::size_t split_edges(EdgesToSplitContainer& edges_to_split,
|
||||
TriangleMesh& tm_S,
|
||||
VPMS vpm_S,
|
||||
TriangleMesh& tm_T,
|
||||
VPMT vpm_T,
|
||||
const GeomTraits& gt,
|
||||
Visitor& visitor,
|
||||
const bool is_source_mesh_fixed) // when snapping is B --> A and the mesh B is fixed
|
||||
{
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG
|
||||
|
|
@ -611,10 +637,14 @@ std::size_t split_edges(EdgesToSplitContainer& edges_to_split,
|
|||
typedef std::vector<Vertex_with_new_position> Vertices_with_new_position;
|
||||
typedef std::pair<const halfedge_descriptor, Vertices_with_new_position> Edge_and_splitters;
|
||||
|
||||
std::size_t snapped_n = 0;
|
||||
|
||||
#ifdef CGAL_PMP_SNAPPING_PRINT_RUNTIME
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
visitor.start_vertex_edge_snapping();
|
||||
|
||||
std::size_t snapped_n = 0;
|
||||
|
||||
for(Edge_and_splitters& es : edges_to_split)
|
||||
{
|
||||
|
|
@ -642,6 +672,9 @@ std::size_t split_edges(EdgesToSplitContainer& edges_to_split,
|
|||
Point previous_split_position = get(vpm_S, *(vertices(tm_S).begin())); // dummy value to avoid "used uninitialized" warning
|
||||
for(const Vertex_with_new_position& vnp : splitters)
|
||||
{
|
||||
if(visitor.stop())
|
||||
return snapped_n;
|
||||
|
||||
const halfedge_descriptor splitter_h = vnp.first;
|
||||
const vertex_descriptor splitter_v = target(splitter_h, tm_S);
|
||||
const Point new_position = is_source_mesh_fixed ? get(vpm_S, splitter_v) : vnp.second;
|
||||
|
|
@ -668,9 +701,13 @@ std::size_t split_edges(EdgesToSplitContainer& edges_to_split,
|
|||
vertex_descriptor new_v = boost::graph_traits<TriangleMesh>::null_vertex();
|
||||
if(do_split)
|
||||
{
|
||||
visitor.before_vertex_edge_snap(h_to_split, tm_T, vnp.second);
|
||||
|
||||
CGAL::Euler::split_edge(h_to_split, tm_T);
|
||||
new_v = source(h_to_split, tm_T);
|
||||
put(vpm_T, new_v, new_position); // position of the new point on the target mesh
|
||||
|
||||
visitor.after_vertex_edge_snap(new_v, tm_T);
|
||||
}
|
||||
|
||||
if(!is_source_mesh_fixed)
|
||||
|
|
@ -740,6 +777,13 @@ std::size_t split_edges(EdgesToSplitContainer& edges_to_split,
|
|||
}
|
||||
}
|
||||
|
||||
visitor.end_vertex_edge_snapping();
|
||||
|
||||
#ifdef CGAL_PMP_SNAPPING_PRINT_RUNTIME
|
||||
timer.stop();
|
||||
std::cout << "time for actual snapping (vertex-edge) " << timer.time() << " s." << std::endl;
|
||||
#endif
|
||||
|
||||
return snapped_n;
|
||||
}
|
||||
|
||||
|
|
@ -757,6 +801,7 @@ template <typename ConcurrencyTag = CGAL::Sequential_tag,
|
|||
typename HalfedgeRange, typename TriangleMesh,
|
||||
typename LockedVertexMap, typename LockedHalfedgeMap, typename ToleranceMap,
|
||||
typename VertexPatchMap_S, typename FacePatchMap_T,
|
||||
typename Visitor,
|
||||
typename SourceNamedParameters, typename TargetNamedParameters>
|
||||
std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
||||
TriangleMesh& tm_S,
|
||||
|
|
@ -768,6 +813,7 @@ std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
|||
FacePatchMap_T face_patch_map_T,
|
||||
LockedHalfedgeMap locked_halfedges_T,
|
||||
const bool is_source_mesh_fixed,
|
||||
Visitor& visitor,
|
||||
const SourceNamedParameters& snp,
|
||||
const TargetNamedParameters& tnp)
|
||||
{
|
||||
|
|
@ -839,7 +885,7 @@ std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
|||
for(auto& p : vertices_to_snap)
|
||||
p.second = point_tolerance_map[get(vpm_S, target(p.first, tm_S))];
|
||||
|
||||
// Since we're inserting primitives one by one, we can't pass this shared data in the constructor of the tree
|
||||
// Since primitives are inserted one by one, the shared data cannot be in the constructor of the tree
|
||||
AABB_Traits aabb_traits;
|
||||
aabb_traits.set_shared_data(tm_T, vpm_T);
|
||||
AABB_tree aabb_tree(aabb_traits);
|
||||
|
|
@ -863,10 +909,15 @@ std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
|||
std::cout << "Collect edges to split with " << vertices_to_snap.size() << " vertices" << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_PMP_SNAPPING_PRINT_RUNTIME
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
#ifndef CGAL_LINKED_WITH_TBB
|
||||
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
#else
|
||||
#else // CGAL_LINKED_WITH_TBB
|
||||
if(std::is_convertible<ConcurrencyTag, Parallel_tag>::value)
|
||||
{
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG
|
||||
|
|
@ -875,22 +926,45 @@ std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
|||
|
||||
typedef tbb::concurrent_hash_map<halfedge_descriptor,
|
||||
Vertices_with_new_position> Concurrent_edge_to_split_container;
|
||||
typedef internal::Find_splittable_edge_for_parallel_for<
|
||||
typedef internal::Parallel_find_splittable_edge<
|
||||
Vertices_with_tolerance, TriangleMesh,
|
||||
Concurrent_edge_to_split_container, AABB_tree,
|
||||
VertexPatchMap_S, FacePatchMap_T, VPMS, VPMT, GT> Functor;
|
||||
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
VertexPatchMap_S, FacePatchMap_T, VPMS, VPMT, GT, Visitor> Functor;
|
||||
|
||||
Concurrent_edge_to_split_container edges_to_split;
|
||||
Functor f(vertices_to_snap, edges_to_split, &aabb_tree,
|
||||
tm_S, vertex_patch_map_S, vpm_S, tm_T, face_patch_map_T, vpm_T, gt);
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, vertices_to_snap.size()), f);
|
||||
tm_S, vertex_patch_map_S, vpm_S, tm_T, face_patch_map_T, vpm_T,
|
||||
gt, visitor);
|
||||
|
||||
std::cout << "Time to gather edges: " << timer.time() << std::endl;
|
||||
try
|
||||
{
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, vertices_to_snap.size()), f);
|
||||
}
|
||||
catch(const CGAL::internal::Throw_at_output_exception&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#if TBB_USE_CAPTURED_EXCEPTION
|
||||
catch(const tbb::captured_exception& e)
|
||||
{
|
||||
const std::string tn1(e.name());
|
||||
const std::string tn2(typeid(const CGAL::internal::Throw_at_output_exception&).name());
|
||||
if(tn1 != tn2)
|
||||
{
|
||||
std::cerr << "Unexpected throw: " << tn1 << std::endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_PMP_SNAPPING_PRINT_RUNTIME
|
||||
timer.stop();
|
||||
std::cout << "time for find split edges (parallel): " << timer.time() << std::endl;
|
||||
#endif
|
||||
|
||||
return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, visitor, is_source_mesh_fixed);
|
||||
}
|
||||
else
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
|
@ -900,14 +974,28 @@ std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S,
|
|||
#endif
|
||||
|
||||
std::map<halfedge_descriptor, Vertices_with_new_position> edges_to_split;
|
||||
for(const Vertex_with_tolerance& vt : vertices_to_snap)
|
||||
|
||||
try
|
||||
{
|
||||
internal::find_splittable_edge(vt, edges_to_split, &aabb_tree,
|
||||
tm_S, vertex_patch_map_S, vpm_S,
|
||||
tm_T, face_patch_map_T, vpm_T, gt);
|
||||
for(const Vertex_with_tolerance& vt : vertices_to_snap)
|
||||
{
|
||||
internal::find_splittable_edge(vt, edges_to_split, &aabb_tree,
|
||||
tm_S, vertex_patch_map_S, vpm_S,
|
||||
tm_T, face_patch_map_T, vpm_T,
|
||||
gt, visitor);
|
||||
}
|
||||
}
|
||||
catch(const CGAL::internal::Throw_at_output_exception&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed);
|
||||
#ifdef CGAL_PMP_SNAPPING_PRINT_RUNTIME
|
||||
timer.stop();
|
||||
std::cout << "time for find split edges (sequential): " << timer.time() << std::endl;
|
||||
#endif
|
||||
|
||||
return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, visitor, is_source_mesh_fixed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -999,15 +1087,28 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
internal_np::face_patch_t, NamedParameters_B,
|
||||
Constant_property_map<face_descriptor, std::size_t> /*default*/ >::type Face_patch_map_B;
|
||||
|
||||
typedef typename internal_np::Lookup_named_param_def <
|
||||
internal_np::visitor_t,
|
||||
NamedParameters_A,
|
||||
internal::Snapping_default_visitor<TriangleMesh> // default
|
||||
>::reference Visitor;
|
||||
|
||||
using CGAL::parameters::choose_parameter;
|
||||
using CGAL::parameters::is_default_parameter;
|
||||
using CGAL::parameters::get_parameter;
|
||||
using CGAL::parameters::get_parameter_reference;
|
||||
|
||||
const bool is_same_mesh = (&tm_A == &tm_B);
|
||||
const bool simplify_first_mesh = choose_parameter(get_parameter(np_A, internal_np::do_simplify_border), false);
|
||||
const bool simplify_second_mesh = choose_parameter(get_parameter(np_B, internal_np::do_simplify_border), false);
|
||||
const bool is_second_mesh_fixed = choose_parameter(get_parameter(np_B, internal_np::do_lock_mesh), false);
|
||||
|
||||
internal::Snapping_default_visitor<TriangleMesh> default_visitor;
|
||||
Visitor& visitor = choose_parameter(get_parameter_reference(np_A, internal_np::visitor), default_visitor);
|
||||
|
||||
if(visitor.stop())
|
||||
return 0;
|
||||
|
||||
// vertex-vertex and vertex-edge snapping is only considered within compatible patches
|
||||
Face_patch_map_A face_patch_map_A = choose_parameter(get_parameter(np_A, internal_np::face_patch),
|
||||
Constant_property_map<face_descriptor, std::size_t>(-1));
|
||||
|
|
@ -1053,6 +1154,9 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
/// #1 and #1bis (Simplification of borders)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if(visitor.stop())
|
||||
return 0;
|
||||
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG
|
||||
std::cout << "Simplify ranges (" << simplify_first_mesh << " " << simplify_second_mesh << ")..." << std::endl;
|
||||
#endif
|
||||
|
|
@ -1079,6 +1183,8 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
/// #2 (Two-way vertex-vertex snapping)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::size_t snapped_n = 0;
|
||||
|
||||
// We keep in memory pairs of source/target edges that are stitchable after vertex-vertex snapping
|
||||
// --> these halfedges should not be considered as targets in non-conformal snapping
|
||||
// Similarly, matching vertices whose incident edges have matching directions are also locked
|
||||
|
|
@ -1087,8 +1193,6 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
Locked_halfedges locked_halfedges_A = get(Halfedge_bool_tag(), tm_A);
|
||||
Locked_halfedges locked_halfedges_B = get(Halfedge_bool_tag(), tm_B);
|
||||
|
||||
std::size_t snapped_n = 0;
|
||||
|
||||
std::vector<std::pair<vertex_descriptor, vertex_descriptor> > locked_vertices;
|
||||
std::vector<halfedge_descriptor> locked_halfedges_A_vector, locked_halfedges_B_vector;
|
||||
|
||||
|
|
@ -1130,17 +1234,24 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// #3 (Two one-way vertex-edge snapping)
|
||||
/// #3 (Two one-way vertex-edge snappings)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if(visitor.stop())
|
||||
return snapped_n;
|
||||
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG
|
||||
std::cout << " ///////////// Two one-way vertex-edge snapping (A --> B) " << std::endl;
|
||||
#endif
|
||||
|
||||
visitor.start_first_vertex_edge_phase();
|
||||
|
||||
snapped_n += internal::snap_non_conformal_one_way<ConcurrencyTag>(
|
||||
halfedge_range_A, tm_A, tolerance_map_A, vertex_patch_map_A, locked_vertices_A,
|
||||
halfedge_range_B, tm_B, face_patch_map_B, locked_halfedges_B,
|
||||
false /*source is never fixed*/, np_A, np_B);
|
||||
false /*source is never fixed*/, visitor, np_A, np_B);
|
||||
|
||||
visitor.end_first_vertex_edge_phase();
|
||||
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT
|
||||
std::ofstream("results/vertex_edge_A.off") << std::setprecision(17) << tm_A;
|
||||
|
|
@ -1149,14 +1260,21 @@ std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A,
|
|||
|
||||
if(!is_self_snapping)
|
||||
{
|
||||
if(visitor.stop())
|
||||
return snapped_n;
|
||||
|
||||
#ifdef CGAL_PMP_SNAP_DEBUG
|
||||
std::cout << " ///////////// Two one-way vertex-edge snapping (B --> A) " << std::endl;
|
||||
std::cout << " ///////////// Two one-way vertex-edge snapping (B --> A) " << std::endl;
|
||||
#endif
|
||||
|
||||
visitor.start_second_vertex_edge_phase();
|
||||
|
||||
snapped_n += internal::snap_non_conformal_one_way<ConcurrencyTag>(
|
||||
halfedge_range_B, tm_B, tolerance_map_B, vertex_patch_map_B, locked_vertices_B,
|
||||
halfedge_range_A, tm_A, face_patch_map_A, locked_halfedges_A,
|
||||
is_second_mesh_fixed, np_B, np_A);
|
||||
is_second_mesh_fixed, visitor, np_B, np_A);
|
||||
|
||||
visitor.end_second_vertex_edge_phase();
|
||||
}
|
||||
|
||||
return snapped_n;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue