mirror of https://github.com/CGAL/cgal
optimized one-sided parallel version
This commit is contained in:
parent
9117c7ea2f
commit
e3c693caac
|
|
@ -1325,6 +1325,8 @@ template< class Kernel,
|
|||
class TriangleMesh2,
|
||||
class VPM1,
|
||||
class VPM2,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2,
|
||||
class TM1Tree,
|
||||
class TM2Tree,
|
||||
class FaceHandle1,
|
||||
|
|
@ -1336,6 +1338,8 @@ std::pair<typename Kernel::FT, bool> preprocess_bounded_error_Hausdorff_impl(
|
|||
const VPM1& vpm1,
|
||||
const VPM2& vpm2,
|
||||
const bool is_one_sided_distance,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
TM1Tree& tm1_tree,
|
||||
TM2Tree& tm2_tree,
|
||||
std::vector<FaceHandle1>& tm1_only,
|
||||
|
|
@ -1376,7 +1380,7 @@ std::pair<typename Kernel::FT, bool> preprocess_bounded_error_Hausdorff_impl(
|
|||
bool rebuild = false;
|
||||
if (compare_meshes) { // exact check
|
||||
match_faces(tm1, tm2, std::back_inserter(common),
|
||||
std::back_inserter(tm1_only), std::back_inserter(tm2_only));
|
||||
std::back_inserter(tm1_only), std::back_inserter(tm2_only), np1, np2);
|
||||
|
||||
// std::cout << "- common: " << common.size() << std::endl;
|
||||
// std::cout << "- tm1 only: " << tm1_only.size() << std::endl;
|
||||
|
|
@ -1651,83 +1655,50 @@ double bounded_error_Hausdorff_impl(
|
|||
return hdist;
|
||||
}
|
||||
|
||||
#if defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS!
|
||||
|
||||
// TODO: && METIS!
|
||||
#if defined(CGAL_LINKED_WITH_TBB)
|
||||
template< class TriangleMesh1,
|
||||
class TriangleMesh2,
|
||||
class VPM1,
|
||||
class VPM2,
|
||||
class TM1Tree,
|
||||
class TM2Tree,
|
||||
class Kernel>
|
||||
struct Bounded_error_preprocessing {
|
||||
|
||||
using FT = typename Kernel::FT;
|
||||
using Timer = CGAL::Real_timer;
|
||||
|
||||
using Face_handle_1 = typename boost::graph_traits<TriangleMesh1>::face_descriptor;
|
||||
using Face_handle_2 = typename boost::graph_traits<TriangleMesh2>::face_descriptor;
|
||||
|
||||
const std::vector<TriangleMesh1>& tm1_parts; const TriangleMesh2& tm2;
|
||||
const bool compare_meshes; const VPM1& vpm1; const VPM2& vpm2;
|
||||
const bool is_one_sided_distance;
|
||||
std::vector<TM1Tree>& tm1_trees;
|
||||
FT infinity_value;
|
||||
const std::vector<TriangleMesh1>& tm1_parts;
|
||||
const VPM1& vpm1; std::vector<TM1Tree>& tm1_trees;
|
||||
|
||||
// Constructor.
|
||||
Bounded_error_preprocessing(
|
||||
const std::vector<TriangleMesh1>& tm1_parts, const TriangleMesh2& tm2,
|
||||
const bool compare_meshes, const VPM1& vpm1, const VPM2& vpm2,
|
||||
const bool is_one_sided_distance,
|
||||
const std::vector<TriangleMesh1>& tm1_parts, const VPM1& vpm1,
|
||||
std::vector<TM1Tree>& tm1_trees) :
|
||||
tm1_parts(tm1_parts), tm2(tm2),
|
||||
compare_meshes(compare_meshes), vpm1(vpm1), vpm2(vpm2),
|
||||
is_one_sided_distance(is_one_sided_distance),
|
||||
tm1_trees(tm1_trees),
|
||||
infinity_value(-FT(1))
|
||||
{ }
|
||||
tm1_parts(tm1_parts), vpm1(vpm1), tm1_trees(tm1_trees) {
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
}
|
||||
|
||||
// Split constructor.
|
||||
Bounded_error_preprocessing(
|
||||
Bounded_error_preprocessing& s, tbb::split) :
|
||||
tm1_parts(s.tm1_parts), tm2(s.tm2),
|
||||
compare_meshes(s.compare_meshes), vpm1(s.vpm1), vpm2(s.vpm2),
|
||||
is_one_sided_distance(s.is_one_sided_distance),
|
||||
tm1_trees(s.tm1_trees),
|
||||
infinity_value(s.infinity_value)
|
||||
{ }
|
||||
tm1_parts(s.tm1_parts), vpm1(s.vpm1), tm1_trees(s.tm1_trees) {
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
}
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& range) {
|
||||
|
||||
TM2Tree tm2_tree;
|
||||
std::vector<Face_handle_1> tm1_only;
|
||||
std::vector<Face_handle_2> tm2_only;
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
|
||||
Timer timer;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
FT max_inf_value = -FT(1);
|
||||
for (std::size_t i = range.begin(); i != range.end(); ++i) {
|
||||
CGAL_assertion(i < tm1_parts.size());
|
||||
CGAL_assertion(i < tm1_trees.size());
|
||||
tm1_only.clear();
|
||||
tm2_only.clear();
|
||||
tm2_tree.clear();
|
||||
const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]);
|
||||
const FT inf_value = preprocess_bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1_parts[i], tm2, compare_meshes, tm1_part_vpm, vpm2, is_one_sided_distance,
|
||||
tm1_trees[i], tm2_tree, tm1_only, tm2_only).first;
|
||||
if (inf_value > max_inf_value) max_inf_value = inf_value;
|
||||
const auto& tm1 = tm1_parts[i];
|
||||
auto& tm1_tree = tm1_trees[i];
|
||||
tm1_tree.insert(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1);
|
||||
tm1_tree.build();
|
||||
}
|
||||
if (max_inf_value > infinity_value) infinity_value = max_inf_value;
|
||||
timer.stop();
|
||||
// std::cout << "* time operator() preprocessing (sec.): " << timer.time() << std::endl;
|
||||
}
|
||||
|
||||
void join(Bounded_error_preprocessing& rhs) {
|
||||
infinity_value = (CGAL::max)(rhs.infinity_value, infinity_value);
|
||||
}
|
||||
void join(Bounded_error_preprocessing&) { }
|
||||
};
|
||||
|
||||
template< class TriangleMesh1,
|
||||
|
|
@ -1757,8 +1728,9 @@ struct Bounded_error_distance_computation {
|
|||
tm1_parts(tm1_parts), tm2(tm2),
|
||||
error_bound(error_bound), vpm1(vpm1), vpm2(vpm2),
|
||||
infinity_value(infinity_value), initial_lower_bound(initial_lower_bound),
|
||||
tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0)
|
||||
{ }
|
||||
tm1_trees(tm1_trees), tm2_tree(tm2_tree), distance(-1.0) {
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
}
|
||||
|
||||
// Split constructor.
|
||||
Bounded_error_distance_computation(
|
||||
|
|
@ -1766,25 +1738,23 @@ struct Bounded_error_distance_computation {
|
|||
tm1_parts(s.tm1_parts), tm2(s.tm2),
|
||||
error_bound(s.error_bound), vpm1(s.vpm1), vpm2(s.vpm2),
|
||||
infinity_value(s.infinity_value), initial_lower_bound(s.initial_lower_bound),
|
||||
tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0)
|
||||
{ }
|
||||
tm1_trees(s.tm1_trees), tm2_tree(s.tm2_tree), distance(-1.0) {
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
}
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& range) {
|
||||
CGAL_assertion(tm1_parts.size() == tm1_trees.size());
|
||||
|
||||
Timer timer;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
double hdist = -1.0;
|
||||
// std::cout << "* range size: " << range.size() << std::endl;
|
||||
for (std::size_t i = range.begin(); i != range.end(); ++i) {
|
||||
CGAL_assertion(i < tm1_parts.size());
|
||||
CGAL_assertion(i < tm1_trees.size());
|
||||
// std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl;
|
||||
const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[i]);
|
||||
const auto& tm1 = tm1_parts[i];
|
||||
const auto& tm1_tree = tm1_trees[i];
|
||||
const double dist = bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1_parts[i], tm2, error_bound, tm1_part_vpm, vpm2,
|
||||
infinity_value, initial_lower_bound, tm1_trees[i], tm2_tree);
|
||||
tm1, tm2, error_bound, vpm1, vpm2,
|
||||
infinity_value, initial_lower_bound, tm1_tree, tm2_tree);
|
||||
if (dist > hdist) hdist = dist;
|
||||
}
|
||||
if (hdist > distance) distance = hdist;
|
||||
|
|
@ -1796,7 +1766,6 @@ struct Bounded_error_distance_computation {
|
|||
distance = (CGAL::max)(rhs.distance, distance);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // defined(CGAL_LINKED_WITH_TBB) && METIS
|
||||
|
||||
template< class Concurrency_tag,
|
||||
|
|
@ -1804,28 +1773,46 @@ template< class Concurrency_tag,
|
|||
class TriangleMesh1,
|
||||
class TriangleMesh2,
|
||||
class VPM1,
|
||||
class VPM2>
|
||||
class VPM2,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
double bounded_error_one_sided_Hausdorff_impl(
|
||||
const TriangleMesh1& tm1,
|
||||
const TriangleMesh2& tm2,
|
||||
const typename Kernel::FT error_bound,
|
||||
const bool compare_meshes,
|
||||
const VPM1& vpm1,
|
||||
const VPM2& vpm2)
|
||||
const VPM2& vpm2,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2)
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
#if !defined(CGAL_LINKED_WITH_TBB)
|
||||
CGAL_static_assertion_msg(
|
||||
!(boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
#endif
|
||||
|
||||
using TM1_primitive = AABB_face_graph_triangle_primitive<TriangleMesh1, VPM1>;
|
||||
using TM2_primitive = AABB_face_graph_triangle_primitive<TriangleMesh2, VPM2>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Point_3 = typename Kernel::Point_3;
|
||||
|
||||
using TM1 = TriangleMesh1;
|
||||
using TM2 = TriangleMesh2;
|
||||
using TMF = CGAL::Face_filtered_graph<TM1>;
|
||||
|
||||
using TM1_primitive = AABB_face_graph_triangle_primitive<TM1, VPM1>;
|
||||
using TM2_primitive = AABB_face_graph_triangle_primitive<TM2, VPM2>;
|
||||
using TMF_primitive = AABB_face_graph_triangle_primitive<TMF, VPM1>;
|
||||
|
||||
using TM1_traits = AABB_traits<Kernel, TM1_primitive>;
|
||||
using TM2_traits = AABB_traits<Kernel, TM2_primitive>;
|
||||
using TMF_traits = AABB_traits<Kernel, TMF_primitive>;
|
||||
|
||||
using TM1_tree = AABB_tree<TM1_traits>;
|
||||
using TM2_tree = AABB_tree<TM2_traits>;
|
||||
using TMF_tree = AABB_tree<TMF_traits>;
|
||||
|
||||
using Face_handle_1 = typename boost::graph_traits<TriangleMesh1>::face_descriptor;
|
||||
using Face_handle_2 = typename boost::graph_traits<TriangleMesh2>::face_descriptor;
|
||||
using Face_handle_1 = typename boost::graph_traits<TM1>::face_descriptor;
|
||||
using Face_handle_2 = typename boost::graph_traits<TM2>::face_descriptor;
|
||||
|
||||
using Timer = CGAL::Real_timer;
|
||||
|
||||
|
|
@ -1834,24 +1821,14 @@ double bounded_error_one_sided_Hausdorff_impl(
|
|||
|
||||
const int nb_cores = 4; // TODO: add to NP!
|
||||
|
||||
TM1_tree tm1_tree;
|
||||
TM2_tree tm2_tree;
|
||||
std::vector<TM1_tree> tm1_trees;
|
||||
std::vector<TriangleMesh1> tm1_parts;
|
||||
std::atomic<FT> infinity_value;
|
||||
|
||||
bool rebuild = false;
|
||||
std::vector<Face_handle_1> tm1_only;
|
||||
std::vector<Face_handle_2> tm2_only;
|
||||
|
||||
#if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS!
|
||||
|
||||
CGAL_static_assertion_msg(
|
||||
!(boost::is_convertible<TAG, CGAL::Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
infinity_value = -FT(1);
|
||||
|
||||
#else
|
||||
std::vector<TMF> tm1_parts;
|
||||
std::vector<TMF_tree> tm1_trees;
|
||||
FT infinity_value = -FT(1);
|
||||
|
||||
// TODO: && METIS!
|
||||
#if defined(CGAL_LINKED_WITH_TBB)
|
||||
if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value && nb_cores > 1) {
|
||||
|
||||
// (1) -- Create partition of tm1.
|
||||
|
|
@ -1863,69 +1840,67 @@ double bounded_error_one_sided_Hausdorff_impl(
|
|||
tm1, nb_cores, CGAL::parameters::
|
||||
face_partition_id_map(face_pid_map));
|
||||
timer.stop();
|
||||
std::cout << "* computing partition time (sec.): " << timer.time() << std::endl;
|
||||
const double time1 = timer.time();
|
||||
std::cout << "- computing partition time (sec.): " << time1 << std::endl;
|
||||
|
||||
// (2) -- Create a filtered face graph for each part.
|
||||
timer.reset();
|
||||
timer.start();
|
||||
using Filtered_graph = CGAL::Face_filtered_graph<TriangleMesh1>;
|
||||
tm1_parts.resize(nb_cores);
|
||||
tm1_parts.reserve(nb_cores);
|
||||
for (int i = 0; i < nb_cores; ++i) {
|
||||
Filtered_graph tm1_part(tm1, i, face_pid_map);
|
||||
CGAL_assertion(tm1_part.is_selection_valid());
|
||||
CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future!
|
||||
std::cout << "* part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl;
|
||||
tm1_parts.emplace_back(tm1, i, face_pid_map);
|
||||
CGAL_assertion(tm1_parts.back().is_selection_valid());
|
||||
std::cout << "* part " << i << " size: " << tm1_parts.back().number_of_faces() << std::endl;
|
||||
}
|
||||
CGAL_assertion(tm1_parts.size() == nb_cores);
|
||||
timer.stop();
|
||||
std::cout << "* creating graphs time (sec.): " << timer.time() << std::endl;
|
||||
const double time2 = timer.time();
|
||||
std::cout << "- creating graphs time (sec.): " << time2 << std::endl;
|
||||
|
||||
// (3) -- Preprocess all input data.
|
||||
timer.reset();
|
||||
timer.start();
|
||||
// std::cout << "* preprocessing parallel version " << std::endl;
|
||||
tm1_trees.resize(tm1_parts.size());
|
||||
|
||||
FT inf_value = -FT(1);
|
||||
const auto tm1_part_vpm = get_const_property_map(CGAL::vertex_point, tm1_parts[0]);
|
||||
std::tie(inf_value, rebuild) = preprocess_bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1_parts[0], tm2, compare_meshes, tm1_part_vpm, vpm2,
|
||||
true, tm1_trees[0], tm2_tree, tm1_only, tm2_only);
|
||||
CGAL_assertion(!rebuild);
|
||||
|
||||
Bounded_error_preprocessing<TriangleMesh1, TriangleMesh2, VPM1, VPM2, TM1_tree, TM2_tree, Kernel> bep(
|
||||
tm1_parts, tm2, compare_meshes, vpm1, vpm2, true, tm1_trees);
|
||||
tbb::parallel_reduce(tbb::blocked_range<std::size_t>(1, tm1_parts.size()), bep);
|
||||
infinity_value = (CGAL::max)(inf_value, bep.infinity_value);
|
||||
// Compute infinity value.
|
||||
const auto bbox1 = bbox(tm1);
|
||||
const auto bbox2 = bbox(tm2);
|
||||
const auto bb = bbox1 + bbox2;
|
||||
const FT sq_dist = CGAL::squared_distance(
|
||||
Point_3(bb.xmin(), bb.ymin(), bb.zmin()),
|
||||
Point_3(bb.xmax(), bb.ymax(), bb.zmax()));
|
||||
infinity_value = CGAL::approximate_sqrt(sq_dist) * FT(2);
|
||||
|
||||
Bounded_error_preprocessing<TMF, VPM1, TMF_tree, Kernel> bep(tm1_parts, vpm1, tm1_trees);
|
||||
tbb::parallel_reduce(tbb::blocked_range<std::size_t>(0, tm1_parts.size()), bep);
|
||||
tm2_tree.insert(faces(tm2).begin(), faces(tm2).end(), tm2, vpm2);
|
||||
tm2_tree.build();
|
||||
for (auto& tm1_tree : tm1_trees) tm1_tree.build();
|
||||
|
||||
timer.stop();
|
||||
std::cout << "* preprocessing parallel time (sec.) " << timer.time() << std::endl;
|
||||
const double time3 = timer.time();
|
||||
std::cout << "- creating trees time (sec.) " << time3 << std::endl;
|
||||
std::cout << "* preprocessing parallel time (sec.) " << time1 + time2 + time3 << std::endl;
|
||||
|
||||
} else // sequential version
|
||||
|
||||
#endif // defined(CGAL_LINKED_WITH_TBB) && METIS
|
||||
|
||||
{
|
||||
// std::cout << "* preprocessing sequential version " << std::endl;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
tm1_trees.resize(1);
|
||||
bool rebuild = false;
|
||||
std::vector<Face_handle_1> tm1_only;
|
||||
std::vector<Face_handle_2> tm2_only;
|
||||
std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1, tm2, compare_meshes, vpm1, vpm2,
|
||||
true, tm1_trees[0], tm2_tree, tm1_only, tm2_only);
|
||||
tm1, tm2, compare_meshes, vpm1, vpm2, true, np1, np2,
|
||||
tm1_tree, tm2_tree, tm1_only, tm2_only);
|
||||
CGAL_assertion(!rebuild);
|
||||
|
||||
tm1_tree.build();
|
||||
tm2_tree.build();
|
||||
tm1_trees[0].build();
|
||||
|
||||
timer.stop();
|
||||
std::cout << "* preprocessing sequential time (sec.) " << timer.time() << std::endl;
|
||||
}
|
||||
|
||||
// std::cout << "* infinity_value: " << infinity_value << std::endl;
|
||||
|
||||
std::cout << "* infinity_value: " << infinity_value << std::endl;
|
||||
if (infinity_value < FT(0)) {
|
||||
// std::cout << "* culling rate: 100%" << std::endl;
|
||||
return 0.0; // TM1 is part of TM2 so the distance is zero
|
||||
|
|
@ -1938,31 +1913,24 @@ double bounded_error_one_sided_Hausdorff_impl(
|
|||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
#if !defined(CGAL_LINKED_WITH_TBB) // TODO: && METIS!
|
||||
|
||||
CGAL_static_assertion_msg(
|
||||
!(boost::is_convertible<TAG, CGAL::Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
hdist = -1.0;
|
||||
|
||||
#else
|
||||
|
||||
// TODO: && METIS!
|
||||
#if defined(CGAL_LINKED_WITH_TBB)
|
||||
if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value && nb_cores > 1) {
|
||||
|
||||
std::cout << "* executing parallel version " << std::endl;
|
||||
Bounded_error_distance_computation<TriangleMesh1, TriangleMesh2, VPM1, VPM2, TM1_tree, TM2_tree, Kernel> bedc(
|
||||
Bounded_error_distance_computation<TMF, TM2, VPM1, VPM2, TMF_tree, TM2_tree, Kernel> bedc(
|
||||
tm1_parts, tm2, error_bound, vpm1, vpm2,
|
||||
infinity_value, initial_lower_bound, tm1_trees, tm2_tree);
|
||||
tbb::parallel_reduce(tbb::blocked_range<std::size_t>(0, tm1_parts.size()), bedc);
|
||||
hdist = bedc.distance;
|
||||
} else
|
||||
|
||||
} else // sequential version
|
||||
#endif // defined(CGAL_LINKED_WITH_TBB) && METIS
|
||||
|
||||
{
|
||||
std::cout << "* executing sequential version " << std::endl;
|
||||
hdist = bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1, tm2, error_bound, vpm1, vpm2,
|
||||
infinity_value, initial_lower_bound, tm1_trees[0], tm2_tree);
|
||||
infinity_value, initial_lower_bound, tm1_tree, tm2_tree);
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
|
|
@ -1977,20 +1945,24 @@ template< class Concurrency_tag,
|
|||
class TriangleMesh1,
|
||||
class TriangleMesh2,
|
||||
class VPM1,
|
||||
class VPM2>
|
||||
class VPM2,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
double bounded_error_symmetric_Hausdorff_impl(
|
||||
const TriangleMesh1& tm1,
|
||||
const TriangleMesh2& tm2,
|
||||
const typename Kernel::FT error_bound,
|
||||
const bool compare_meshes,
|
||||
const VPM1& vpm1,
|
||||
const VPM2& vpm2)
|
||||
const VPM2& vpm2,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2)
|
||||
{
|
||||
// Naive version.
|
||||
// const double hdist1 = bounded_error_one_sided_Hausdorff_impl<Concurrency_tag, Kernel>(
|
||||
// tm1, tm2, error_bound, compare_meshes, vpm1, vpm2);
|
||||
// tm1, tm2, error_bound, compare_meshes, vpm1, vpm2, np1, np2);
|
||||
// const double hdist2 = bounded_error_one_sided_Hausdorff_impl<Concurrency_tag, Kernel>(
|
||||
// tm2, tm1, error_bound, compare_meshes, vpm2, vpm1);
|
||||
// tm2, tm1, error_bound, compare_meshes, vpm2, vpm1, np1, np2);
|
||||
// return (CGAL::max)(hdist1, hdist2);
|
||||
|
||||
// Optimized version.
|
||||
|
|
@ -2020,8 +1992,8 @@ double bounded_error_symmetric_Hausdorff_impl(
|
|||
FT infinity_value = -FT(1);
|
||||
bool rebuild = false;
|
||||
std::tie(infinity_value, rebuild) = preprocess_bounded_error_Hausdorff_impl<Kernel>(
|
||||
tm1, tm2, compare_meshes, vpm1, vpm2,
|
||||
false, tm1_tree, tm2_tree, tm1_only, tm2_only);
|
||||
tm1, tm2, compare_meshes, vpm1, vpm2, false, np1, np2,
|
||||
tm1_tree, tm2_tree, tm1_only, tm2_only);
|
||||
|
||||
if (infinity_value < FT(0)) {
|
||||
// std::cout << "* culling rate: 100%" << std::endl;
|
||||
|
|
@ -2260,7 +2232,7 @@ double bounded_error_Hausdorff_distance(
|
|||
CGAL_precondition(error_bound >= 0.0);
|
||||
const FT error_threshold = static_cast<FT>(error_bound);
|
||||
return internal::bounded_error_one_sided_Hausdorff_impl<Concurrency_tag, Traits>(
|
||||
tm1, tm2, error_threshold, match_faces, vpm1, vpm2);
|
||||
tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2);
|
||||
}
|
||||
|
||||
template< class Concurrency_tag,
|
||||
|
|
@ -2335,7 +2307,7 @@ double bounded_error_symmetric_Hausdorff_distance(
|
|||
CGAL_precondition(error_bound >= 0.0);
|
||||
const FT error_threshold = static_cast<FT>(error_bound);
|
||||
return internal::bounded_error_symmetric_Hausdorff_impl<Concurrency_tag, Traits>(
|
||||
tm1, tm2, error_threshold, match_faces, vpm1, vpm2);
|
||||
tm1, tm2, error_threshold, match_faces, vpm1, vpm2, np1, np2);
|
||||
}
|
||||
|
||||
template< class Concurrency_tag,
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@
|
|||
#include <CGAL/Polygon_mesh_processing/random_perturbation.h>
|
||||
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||
|
||||
#include <CGAL/boost/graph/partition.h> // METIS related
|
||||
#include <CGAL/boost/graph/Face_filtered_graph.h>
|
||||
|
||||
using SCK = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
|
@ -26,7 +23,7 @@ using Point_3 = typename Kernel::Point_3;
|
|||
using Vector_3 = typename Kernel::Vector_3;
|
||||
using Triangle_3 = typename Kernel::Triangle_3;
|
||||
|
||||
using TAG = CGAL::Parallel_if_available_tag;
|
||||
using TAG = CGAL::Sequential_tag;
|
||||
using Surface_mesh = CGAL::Surface_mesh<Point_3>;
|
||||
using Affine_transformation_3 = CGAL::Aff_transformation_3<Kernel>;
|
||||
using Timer = CGAL::Real_timer;
|
||||
|
|
@ -821,160 +818,6 @@ void test_realizing_triangles(
|
|||
compute_realizing_triangles(mesh1, mesh2, error_bound, "2", save);
|
||||
}
|
||||
|
||||
// TODO: remove that!
|
||||
#if defined(CGAL_LINKED_WITH_TBB)
|
||||
template<class TriangleMesh1, class TriangleMesh2>
|
||||
struct Bounded_error_distance_computation {
|
||||
|
||||
const std::vector<TriangleMesh1>& tm1_parts;
|
||||
const TriangleMesh2& tm2;
|
||||
const double error_bound;
|
||||
double distance;
|
||||
|
||||
// Constructor.
|
||||
Bounded_error_distance_computation(
|
||||
const std::vector<TriangleMesh1>& tm1_parts,
|
||||
const TriangleMesh2& tm2,
|
||||
const double error_bound) :
|
||||
tm1_parts(tm1_parts), tm2(tm2),
|
||||
error_bound(error_bound), distance(-1.0)
|
||||
{ }
|
||||
|
||||
// Split constructor.
|
||||
Bounded_error_distance_computation(
|
||||
Bounded_error_distance_computation& s, tbb::split) :
|
||||
tm1_parts(s.tm1_parts), tm2(s.tm2),
|
||||
error_bound(s.error_bound), distance(-1.0)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& range) {
|
||||
|
||||
Timer timer;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
// std::cout << "* range size: " << range.size() << std::endl;
|
||||
double hdist = 0.0;
|
||||
for (std::size_t i = range.begin(); i != range.end(); ++i) {
|
||||
CGAL_assertion(i < tm1_parts.size());
|
||||
const auto& tm1 = tm1_parts[i];
|
||||
// std::cout << "part size: " << tm1.number_of_faces() << std::endl;
|
||||
const double dist = PMP::bounded_error_Hausdorff_distance<CGAL::Sequential_tag>(
|
||||
tm1, tm2, error_bound,
|
||||
CGAL::parameters::match_faces(false),
|
||||
CGAL::parameters::match_faces(false));
|
||||
if (dist > hdist) hdist = dist;
|
||||
}
|
||||
if (hdist > distance) distance = hdist;
|
||||
|
||||
timer.stop();
|
||||
// std::cout << "* time operator() (sec.): " << timer.time() << std::endl;
|
||||
}
|
||||
|
||||
void join(Bounded_error_distance_computation& rhs) {
|
||||
distance = (CGAL::max)(rhs.distance, distance);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// TODO: remove that!
|
||||
double bounded_error_Hausdorff_distance_parallel(
|
||||
Surface_mesh& tm1, const Surface_mesh& tm2,
|
||||
const double error_bound, const int nb_cores = 4) {
|
||||
|
||||
Timer timer;
|
||||
|
||||
// (1) -- Create partition of tm1.
|
||||
std::cout << "* computing partition ... " << std::endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
// Partition the mesh and output its parts.
|
||||
using Face_index = typename Surface_mesh::Face_index;
|
||||
auto face_pid_map = tm1.add_property_map<Face_index, std::size_t>("f:pid").first;
|
||||
CGAL::METIS::partition_graph(
|
||||
tm1, nb_cores, CGAL::parameters::
|
||||
face_partition_id_map(face_pid_map));
|
||||
|
||||
int max_id = 0;
|
||||
for (const auto& face : faces(tm1)) {
|
||||
const int id = static_cast<int>(get(face_pid_map, face));
|
||||
max_id = (CGAL::max)(max_id, id);
|
||||
}
|
||||
assert(nb_cores == (max_id + 1));
|
||||
timer.stop();
|
||||
const double time1 = timer.time();
|
||||
std::cout << " ... done in " << time1 << " sec." << std::endl;
|
||||
std::cout << "* number of detected parts: " << max_id + 1 << std::endl;
|
||||
|
||||
// (2) -- Create a face filtered graph for each part.
|
||||
std::cout << "* creating graphs ... " << std::endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
using Filtered_graph = CGAL::Face_filtered_graph<Surface_mesh>;
|
||||
std::vector<Surface_mesh> tm1_parts(nb_cores);
|
||||
for (int i = 0; i < nb_cores; ++i) {
|
||||
// std::cout << "selection " << i << std::endl;
|
||||
Filtered_graph tm1_part(tm1, i, face_pid_map);
|
||||
CGAL_assertion(tm1_part.is_selection_valid());
|
||||
CGAL::copy_face_graph(tm1_part, tm1_parts[i]); // TODO: do not copy in the future!
|
||||
std::cout << "part " << i << " size: " << tm1_parts[i].number_of_faces() << std::endl;
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
const double time2 = timer.time();
|
||||
std::cout << " ... done in " << time2 << " sec." << std::endl;
|
||||
|
||||
// (3) -- Run all parts in parallel.
|
||||
std::cout << "* computing distance for all graphs in parallel ... " << std::endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
std::atomic<double> hdist;
|
||||
#if !defined(CGAL_LINKED_WITH_TBB)
|
||||
CGAL_static_assertion_msg(
|
||||
!(boost::is_convertible<TAG, CGAL::Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
hdist = -1.0;
|
||||
#else
|
||||
if (boost::is_convertible<TAG, CGAL::Parallel_tag>::value) {
|
||||
std::cout << "* executing parallel version " << std::endl;
|
||||
Bounded_error_distance_computation<Surface_mesh, Surface_mesh> f(
|
||||
tm1_parts, tm2, error_bound);
|
||||
tbb::parallel_reduce(tbb::blocked_range<std::size_t>(0, tm1_parts.size()), f);
|
||||
hdist = f.distance;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
std::cout << "* executing sequential version " << std::endl;
|
||||
hdist = PMP::bounded_error_Hausdorff_distance<TAG>(
|
||||
tm1, tm2, error_bound,
|
||||
CGAL::parameters::match_faces(false),
|
||||
CGAL::parameters::match_faces(false));
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
const double time3 = timer.time();
|
||||
std::cout << " ... done in " << time3 << " sec." << std::endl;
|
||||
|
||||
// for (const auto& tm1_part : tm1_parts) {
|
||||
// timer.reset();
|
||||
// timer.start();
|
||||
// hdist = PMP::bounded_error_Hausdorff_distance<CGAL::Sequential_tag>(
|
||||
// tm1_part, tm2, error_bound,
|
||||
// CGAL::parameters::match_faces(false),
|
||||
// CGAL::parameters::match_faces(false));
|
||||
// timer.stop();
|
||||
// std::cout << "* manual call seq. time (sec.): " << timer.time() << std::endl;
|
||||
// }
|
||||
|
||||
return hdist;
|
||||
}
|
||||
|
||||
void test_parallel_version(
|
||||
const std::string filepath, const double error_bound) {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue