12 #ifndef TANGENTIAL_COMPLEX_H_ 13 #define TANGENTIAL_COMPLEX_H_ 15 #include <gudhi/Tangential_complex/config.h> 16 #include <gudhi/Tangential_complex/Simplicial_complex.h> 17 #include <gudhi/Tangential_complex/utilities.h> 18 #include <gudhi/Kd_tree_search.h> 19 #include <gudhi/console_color.h> 20 #include <gudhi/Clock.h> 21 #include <gudhi/Simplex_tree.h> 22 #include <gudhi/Debug_utils.h> 24 #include <CGAL/Default.h> 25 #include <CGAL/Dimension.h> 26 #include <CGAL/function_objects.h> 27 #include <CGAL/Epick_d.h> 28 #include <CGAL/Regular_triangulation_traits_adapter.h> 29 #include <CGAL/Regular_triangulation.h> 30 #include <CGAL/Delaunay_triangulation.h> 31 #include <CGAL/Combination_enumerator.h> 32 #include <CGAL/point_generators_d.h> 33 #include <CGAL/version.h> 36 #include <Eigen/Eigen> 37 #include <Eigen/src/Core/util/Macros.h> 39 #include <boost/optional.hpp> 40 #include <boost/iterator/transform_iterator.hpp> 41 #include <boost/range/adaptor/transformed.hpp> 42 #include <boost/range/counting_range.hpp> 43 #include <boost/math/special_functions/factorials.hpp> 44 #include <boost/container/flat_set.hpp> 61 #include <tbb/parallel_for.h> 62 #include <tbb/combinable.h> 69 #if CGAL_VERSION_NR < 1041101000 70 # error Tangential_complex is only available for CGAL >= 4.11 73 #if !EIGEN_VERSION_AT_LEAST(3,1,0) 74 # error Tangential_complex is only available for Eigen3 >= 3.1.0 installed with CGAL 81 namespace tangential_complex {
83 using namespace internal;
87 Vertex_data(std::size_t data = (std::numeric_limits<std::size_t>::max)()) : m_data(data) {}
89 operator std::size_t() {
return m_data; }
91 operator std::size_t()
const {
return m_data; }
122 template <
typename Kernel_,
123 typename DimensionTag,
124 typename Concurrency_tag = CGAL::Parallel_tag,
typename Triangulation_ = CGAL::Default>
127 typedef typename K::FT FT;
128 typedef typename K::Point_d Point;
129 typedef typename K::Weighted_point_d Weighted_point;
130 typedef typename K::Vector_d Vector;
132 typedef typename CGAL::Default::Get<
134 CGAL::Regular_triangulation<
135 CGAL::Epick_d<DimensionTag>,
136 CGAL::Triangulation_data_structure<
137 typename CGAL::Epick_d<DimensionTag>::Dimension,
138 CGAL::Triangulation_vertex<CGAL::Regular_triangulation_traits_adapter<CGAL::Epick_d<DimensionTag> >,
140 CGAL::Triangulation_full_cell<
141 CGAL::Regular_triangulation_traits_adapter<CGAL::Epick_d<DimensionTag> > > > > >::type Triangulation;
142 typedef typename Triangulation::Geom_traits Tr_traits;
143 typedef typename Triangulation::Weighted_point Tr_point;
144 typedef typename Tr_traits::Base::Point_d Tr_bare_point;
145 typedef typename Triangulation::Vertex_handle Tr_vertex_handle;
146 typedef typename Triangulation::Full_cell_handle Tr_full_cell_handle;
147 typedef typename Tr_traits::Vector_d Tr_vector;
149 #if defined(GUDHI_USE_TBB) 150 typedef std::mutex Mutex_for_perturb;
151 typedef Vector Translation_for_perturb;
152 typedef std::vector<Atomic_wrapper<FT> > Weights;
154 typedef Vector Translation_for_perturb;
155 typedef std::vector<FT> Weights;
157 typedef std::vector<Translation_for_perturb> Translations_for_perturb;
163 Tr_and_VH() : m_tr(NULL) {}
165 Tr_and_VH(
int dim) : m_tr(
new Triangulation(dim)) {}
167 ~Tr_and_VH() { destroy_triangulation(); }
169 Triangulation &construct_triangulation(
int dim) {
171 m_tr =
new Triangulation(dim);
175 void destroy_triangulation() {
180 Triangulation &tr() {
return *m_tr; }
182 Triangulation
const &tr()
const {
return *m_tr; }
184 Tr_vertex_handle
const ¢er_vertex()
const {
return m_center_vertex; }
186 Tr_vertex_handle ¢er_vertex() {
return m_center_vertex; }
190 Tr_vertex_handle m_center_vertex;
194 typedef Basis<K> Tangent_space_basis;
195 typedef Basis<K> Orthogonal_space_basis;
196 typedef std::vector<Tangent_space_basis> TS_container;
197 typedef std::vector<Orthogonal_space_basis> OS_container;
199 typedef std::vector<Point> Points;
201 typedef boost::container::flat_set<std::size_t> Simplex;
202 typedef std::set<Simplex> Simplex_set;
209 typedef std::vector<Tr_and_VH> Tr_container;
210 typedef std::vector<Vector> Vectors;
214 typedef boost::container::flat_set<std::size_t> Incident_simplex;
215 typedef std::vector<Incident_simplex> Star;
216 typedef std::vector<Star> Stars_container;
220 static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) {
return vh->point(); }
222 template <
typename P,
typename VH>
223 static const P &vertex_handle_to_point(VH vh) {
228 typedef internal::Simplicial_complex Simplicial_complex;
239 template <
typename Po
int_range>
241 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
242 InputIterator first_for_tse, InputIterator last_for_tse,
246 m_intrinsic_dim(intrinsic_dimension),
247 m_ambient_dim(points.empty() ? 0 : k.point_dimension_d_object()(*points.begin())),
248 m_points(points.begin(), points.end()),
249 m_weights(m_points.size(), FT(0))
250 #if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
252 m_p_perturb_mutexes(NULL)
255 m_points_ds(m_points),
256 m_last_max_perturb(0.),
257 m_are_tangent_spaces_computed(m_points.size(), false),
258 m_tangent_spaces(m_points.size(), Tangent_space_basis())
259 #ifdef GUDHI_TC_EXPORT_NORMALS
261 m_orth_spaces(m_points.size(), Orthogonal_space_basis())
263 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
265 m_points_for_tse(first_for_tse, last_for_tse),
266 m_points_ds_for_tse(m_points_for_tse)
273 #if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION) 274 delete[] m_p_perturb_mutexes;
284 Points
const &points()
const {
return m_points; }
291 Point
get_point(std::size_t vertex)
const {
return m_points[vertex]; }
304 void set_weights(
const Weights &weights) { m_weights = weights; }
306 void set_tangent_planes(
const TS_container &tangent_spaces
307 #ifdef GUDHI_TC_EXPORT_NORMALS
309 const OS_container &orthogonal_spaces
312 #ifdef GUDHI_TC_EXPORT_NORMALS 313 GUDHI_CHECK(m_points.size() == tangent_spaces.size() && m_points.size() == orthogonal_spaces.size(),
314 std::logic_error(
"Wrong sizes"));
316 GUDHI_CHECK(m_points.size() == tangent_spaces.size(), std::logic_error(
"Wrong sizes"));
318 m_tangent_spaces = tangent_spaces;
319 #ifdef GUDHI_TC_EXPORT_NORMALS 320 m_orth_spaces = orthogonal_spaces;
322 for (std::size_t i = 0; i < m_points.size(); ++i) m_are_tangent_spaces_computed[i] =
true;
331 #ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS 332 std::cerr << red <<
"WARNING: GUDHI_TC_PERFORM_EXTRA_CHECKS is defined. " 333 <<
"Computation might be slower than usual.\n" 337 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB) 344 m_triangulations.resize(m_points.size());
345 m_stars.resize(m_points.size());
346 m_squared_star_spheres_radii_incl_margin.resize(m_points.size(), FT(-1));
347 #ifdef GUDHI_TC_PERTURB_POSITION 348 if (m_points.empty())
349 m_translations.clear();
351 m_translations.resize(m_points.size(), m_k.construct_vector_d_object()(m_ambient_dim));
352 #if defined(GUDHI_USE_TBB) 353 delete[] m_p_perturb_mutexes;
354 m_p_perturb_mutexes =
new Mutex_for_perturb[m_points.size()];
360 if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
361 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*
this));
363 #endif // GUDHI_USE_TBB 365 for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
368 #endif // GUDHI_USE_TBB 370 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB) 372 std::cerr <<
"Tangential complex computed in " << t.num_seconds() <<
" seconds.\n";
379 bool success =
false;
381 unsigned int num_steps = 0;
383 std::size_t initial_num_inconsistent_stars = 0;
385 std::size_t best_num_inconsistent_stars = 0;
387 std::size_t final_num_inconsistent_stars = 0;
398 if (time_limit == 0.)
return info;
402 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES 403 std::tuple<std::size_t, std::size_t, std::size_t> stats_before = number_of_inconsistent_simplices(
false);
405 if (std::get<1>(stats_before) == 0) {
407 std::cerr <<
"Nothing to fix.\n";
412 #endif // GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES 414 m_last_max_perturb = max_perturb;
420 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES 421 std::cerr <<
"\nBefore fix step:\n" 422 <<
" * Total number of simplices in stars (incl. duplicates): " << std::get<0>(stats_before) <<
"\n" 423 <<
" * Num inconsistent simplices in stars (incl. duplicates): " << red << std::get<1>(stats_before)
424 << white <<
" (" << 100. * std::get<1>(stats_before) / std::get<0>(stats_before) <<
"%)\n" 425 <<
" * Number of stars containing inconsistent simplices: " << red << std::get<2>(stats_before)
426 << white <<
" (" << 100. * std::get<2>(stats_before) / m_points.size() <<
"%)\n";
429 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) 430 std::cerr << yellow <<
"\nAttempt to fix inconsistencies using perturbations - step #" << info.
num_steps + 1
434 std::size_t num_inconsistent_stars = 0;
435 std::vector<std::size_t> updated_points;
437 #ifdef GUDHI_TC_PROFILING 438 Gudhi::Clock t_fix_step;
442 #if defined(GUDHI_USE_TBB) 443 if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
444 tbb::combinable<std::size_t> num_inconsistencies;
445 tbb::combinable<std::vector<std::size_t> > tls_updated_points;
446 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_triangulations.size()),
447 Try_to_solve_inconsistencies_in_a_local_triangulation(*
this, max_perturb, num_inconsistencies,
448 tls_updated_points));
449 num_inconsistent_stars = num_inconsistencies.combine(std::plus<std::size_t>());
451 tls_updated_points.combine([](std::vector<std::size_t>
const &x, std::vector<std::size_t>
const &y) {
452 std::vector<std::size_t> res;
453 res.reserve(x.size() + y.size());
454 res.insert(res.end(), x.begin(), x.end());
455 res.insert(res.end(), y.begin(), y.end());
459 #endif // GUDHI_USE_TBB 461 for (std::size_t i = 0; i < m_triangulations.size(); ++i) {
462 num_inconsistent_stars +=
463 try_to_solve_inconsistencies_in_a_local_triangulation(i, max_perturb, std::back_inserter(updated_points));
465 #if defined(GUDHI_USE_TBB) 467 #endif // GUDHI_USE_TBB 469 #ifdef GUDHI_TC_PROFILING 473 #if defined(GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES) || defined(DEBUG_TRACES) 474 std::cerr <<
"\nEncountered during fix:\n" 475 <<
" * Num stars containing inconsistent simplices: " << red << num_inconsistent_stars << white <<
" (" 476 << 100. * num_inconsistent_stars / m_points.size() <<
"%)\n";
479 #ifdef GUDHI_TC_PROFILING 480 std::cerr << yellow <<
"done in " << t_fix_step.num_seconds() <<
" seconds.\n" << white;
481 #elif defined(DEBUG_TRACES) 482 std::cerr << yellow <<
"done.\n" << white;
485 if (num_inconsistent_stars > 0) refresh_tangential_complex(updated_points);
487 #ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS 489 std::size_t num_inc_1 = std::get<1>(number_of_inconsistent_simplices(
false));
490 refresh_tangential_complex();
491 std::size_t num_inc_2 = std::get<1>(number_of_inconsistent_simplices(
false));
492 if (num_inc_1 != num_inc_2)
493 std::cerr << red <<
"REFRESHMENT CHECK: FAILED. (" << num_inc_1 <<
" vs " << num_inc_2 <<
")\n" << white;
495 std::cerr << green <<
"REFRESHMENT CHECK: PASSED.\n" << white;
498 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES 499 std::tuple<std::size_t, std::size_t, std::size_t> stats_after = number_of_inconsistent_simplices(
false);
501 std::cerr <<
"\nAfter fix:\n" 502 <<
" * Total number of simplices in stars (incl. duplicates): " << std::get<0>(stats_after) <<
"\n" 503 <<
" * Num inconsistent simplices in stars (incl. duplicates): " << red << std::get<1>(stats_after)
504 << white <<
" (" << 100. * std::get<1>(stats_after) / std::get<0>(stats_after) <<
"%)\n" 505 <<
" * Number of stars containing inconsistent simplices: " << red << std::get<2>(stats_after) << white
506 <<
" (" << 100. * std::get<2>(stats_after) / m_points.size() <<
"%)\n";
508 stats_before = stats_after;
518 done = (num_inconsistent_stars == 0);
521 if (time_limit > 0. && t.num_seconds() > time_limit) {
523 std::cerr << red <<
"Time limit reached.\n" << white;
532 std::cerr << green <<
"Fixed!\n" << white;
541 std::size_t num_simplices = 0;
543 std::size_t num_inconsistent_simplices = 0;
545 std::size_t num_inconsistent_stars = 0;
561 for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
562 bool is_star_inconsistent =
false;
565 Star::const_iterator it_inc_simplex = m_stars[idx].begin();
566 Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
567 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
569 if (is_infinite(*it_inc_simplex))
continue;
571 Simplex c = *it_inc_simplex;
574 if (!is_simplex_consistent(c)) {
576 is_star_inconsistent =
true;
585 std::cerr <<
"\n==========================================================\n" 586 <<
"Inconsistencies:\n" 587 <<
" * Total number of simplices in stars (incl. duplicates): " << stats.
num_simplices <<
"\n" 588 <<
" * Number of inconsistent simplices in stars (incl. duplicates): " 593 <<
"==========================================================\n";
609 template <
typename Simplex_tree_>
611 bool export_inconsistent_simplices =
true 614 bool export_infinite_simplices =
false, Simplex_set *p_inconsistent_simplices = NULL
617 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) 618 std::cerr << yellow <<
"\nExporting the TC as a Simplex_tree... " << white;
620 #ifdef GUDHI_TC_PROFILING 627 for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
629 Star::const_iterator it_inc_simplex = m_stars[idx].begin();
630 Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
631 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
632 Simplex c = *it_inc_simplex;
635 if (!export_infinite_simplices && is_infinite(c))
continue;
637 if (static_cast<int>(c.size()) > max_dim) max_dim =
static_cast<int>(c.size());
641 if (!export_inconsistent_simplices && !is_simplex_consistent(c))
continue;
644 bool inserted = tree.insert_simplex_and_subfaces(c).second;
647 if (p_inconsistent_simplices && inserted && !is_simplex_consistent(c)) {
648 p_inconsistent_simplices->insert(c);
653 #ifdef GUDHI_TC_PROFILING 655 std::cerr << yellow <<
"done in " << t.num_seconds() <<
" seconds.\n" << white;
656 #elif defined(DEBUG_TRACES) 657 std::cerr << yellow <<
"done.\n" << white;
673 int create_complex(Simplicial_complex &complex,
bool export_inconsistent_simplices =
true,
674 bool export_infinite_simplices =
false,
int check_lower_and_higher_dim_simplices = 2,
675 Simplex_set *p_inconsistent_simplices = NULL)
const {
676 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) 677 std::cerr << yellow <<
"\nExporting the TC as a Simplicial_complex... " << white;
679 #ifdef GUDHI_TC_PROFILING 687 for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
689 Star::const_iterator it_inc_simplex = m_stars[idx].begin();
690 Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
691 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
692 Simplex c = *it_inc_simplex;
695 if (!export_infinite_simplices && is_infinite(c))
continue;
697 if (static_cast<int>(c.size()) > max_dim) max_dim =
static_cast<int>(c.size());
701 if (!export_inconsistent_simplices && !is_simplex_consistent(c))
continue;
704 if (check_lower_and_higher_dim_simplices == 2 && max_dim != -1 && static_cast<int>(c.size()) != max_dim) {
707 <<
"Info: check_lower_and_higher_dim_simplices ACTIVATED. " 708 "Export might be take some time...\n" 710 check_lower_and_higher_dim_simplices = 1;
714 bool added = complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1);
717 if (p_inconsistent_simplices && added && !is_simplex_consistent(c)) {
718 p_inconsistent_simplices->insert(c);
723 #ifdef GUDHI_TC_PROFILING 725 std::cerr << yellow <<
"done in " << t.num_seconds() <<
" seconds.\n" << white;
726 #elif defined(DEBUG_TRACES) 727 std::cerr << yellow <<
"done.\n" << white;
733 template <
typename ProjectionFunctor = CGAL::Identity<Po
int> >
734 std::ostream &export_to_off(
const Simplicial_complex &complex, std::ostream &os,
735 Simplex_set
const *p_simpl_to_color_in_red = NULL,
736 Simplex_set
const *p_simpl_to_color_in_green = NULL,
737 Simplex_set
const *p_simpl_to_color_in_blue = NULL,
738 ProjectionFunctor
const &point_projection = ProjectionFunctor())
const {
739 return export_to_off(os,
false, p_simpl_to_color_in_red, p_simpl_to_color_in_green, p_simpl_to_color_in_blue,
740 &complex, point_projection);
743 template <
typename ProjectionFunctor = CGAL::Identity<Po
int> >
744 std::ostream &export_to_off(std::ostream &os,
bool color_inconsistencies =
false,
745 Simplex_set
const *p_simpl_to_color_in_red = NULL,
746 Simplex_set
const *p_simpl_to_color_in_green = NULL,
747 Simplex_set
const *p_simpl_to_color_in_blue = NULL,
748 const Simplicial_complex *p_complex = NULL,
749 ProjectionFunctor
const &point_projection = ProjectionFunctor())
const {
750 if (m_points.empty())
return os;
752 if (m_ambient_dim < 2) {
753 std::cerr <<
"Error: export_to_off => ambient dimension should be >= 2.\n";
754 os <<
"Error: export_to_off => ambient dimension should be >= 2.\n";
757 if (m_ambient_dim > 3) {
758 std::cerr <<
"Warning: export_to_off => ambient dimension should be " 759 "<= 3. Only the first 3 coordinates will be exported.\n";
762 if (m_intrinsic_dim < 1 || m_intrinsic_dim > 3) {
763 std::cerr <<
"Error: export_to_off => intrinsic dimension should be " 764 "between 1 and 3.\n";
765 os <<
"Error: export_to_off => intrinsic dimension should be " 766 "between 1 and 3.\n";
770 std::stringstream output;
771 std::size_t num_simplices, num_vertices;
772 export_vertices_to_off(output, num_vertices,
false, point_projection);
774 export_simplices_to_off(*p_complex, output, num_simplices, p_simpl_to_color_in_red, p_simpl_to_color_in_green,
775 p_simpl_to_color_in_blue);
777 export_simplices_to_off(output, num_simplices, color_inconsistencies, p_simpl_to_color_in_red,
778 p_simpl_to_color_in_green, p_simpl_to_color_in_blue);
781 #ifdef GUDHI_TC_EXPORT_NORMALS 786 << num_vertices <<
" " << num_simplices <<
" " 794 void refresh_tangential_complex() {
795 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) 796 std::cerr << yellow <<
"\nRefreshing TC... " << white;
799 #ifdef GUDHI_TC_PROFILING 804 if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
805 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*
this));
807 #endif // GUDHI_USE_TBB 809 for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
812 #endif // GUDHI_USE_TBB 814 #ifdef GUDHI_TC_PROFILING 816 std::cerr << yellow <<
"done in " << t.num_seconds() <<
" seconds.\n" << white;
817 #elif defined(DEBUG_TRACES) 818 std::cerr << yellow <<
"done.\n" << white;
823 template <
typename Po
int_indices_range>
824 void refresh_tangential_complex(Point_indices_range
const &perturbed_points_indices) {
825 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) 826 std::cerr << yellow <<
"\nRefreshing TC... " << white;
829 #ifdef GUDHI_TC_PROFILING 834 Points_ds updated_pts_ds(m_points, perturbed_points_indices);
838 if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
839 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()),
840 Refresh_tangent_triangulation(*
this, updated_pts_ds));
842 #endif // GUDHI_USE_TBB 844 for (std::size_t i = 0; i < m_points.size(); ++i) refresh_tangent_triangulation(i, updated_pts_ds);
847 #endif // GUDHI_USE_TBB 849 #ifdef GUDHI_TC_PROFILING 851 std::cerr << yellow <<
"done in " << t.num_seconds() <<
" seconds.\n" << white;
852 #elif defined(DEBUG_TRACES) 853 std::cerr << yellow <<
"done.\n" << white;
857 void export_inconsistent_stars_to_OFF_files(std::string
const &filename_base)
const {
859 for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
861 Simplicial_complex sc;
863 bool is_inconsistent =
false;
864 Star::const_iterator it_inc_simplex = m_stars[idx].begin();
865 Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
866 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
868 if (is_infinite(*it_inc_simplex))
continue;
870 Simplex c = *it_inc_simplex;
876 if (!is_inconsistent && !is_simplex_consistent(c)) is_inconsistent =
true;
879 if (is_inconsistent) {
881 std::stringstream output_filename;
882 output_filename << filename_base <<
"_" << idx <<
".off";
883 std::ofstream off_stream(output_filename.str().c_str());
884 export_to_off(sc, off_stream);
889 class Compare_distance_to_ref_point {
891 Compare_distance_to_ref_point(Point
const &ref, K
const &k) : m_ref(ref), m_k(k) {}
893 bool operator()(Point
const &p1, Point
const &p2) {
894 typename K::Squared_distance_d sqdist = m_k.squared_distance_d_object();
895 return sqdist(p1, m_ref) < sqdist(p2, m_ref);
905 class Compute_tangent_triangulation {
913 Compute_tangent_triangulation(
const Compute_tangent_triangulation &ctt) : m_tc(ctt.m_tc) {}
916 void operator()(
const tbb::blocked_range<size_t> &r)
const {
917 for (
size_t i = r.begin(); i != r.end(); ++i) m_tc.compute_tangent_triangulation(i);
922 class Refresh_tangent_triangulation {
924 Points_ds
const &m_updated_pts_ds;
928 Refresh_tangent_triangulation(
Tangential_complex &tc, Points_ds
const &updated_pts_ds)
929 : m_tc(tc), m_updated_pts_ds(updated_pts_ds) {}
932 Refresh_tangent_triangulation(
const Refresh_tangent_triangulation &ctt)
933 : m_tc(ctt.m_tc), m_updated_pts_ds(ctt.m_updated_pts_ds) {}
936 void operator()(
const tbb::blocked_range<size_t> &r)
const {
937 for (
size_t i = r.begin(); i != r.end(); ++i) m_tc.refresh_tangent_triangulation(i, m_updated_pts_ds);
940 #endif // GUDHI_USE_TBB 942 bool is_infinite(Simplex
const &s)
const {
return *s.rbegin() == (std::numeric_limits<std::size_t>::max)(); }
947 Tr_vertex_handle compute_star(std::size_t i,
const Point ¢er_pt,
const Tangent_space_basis &tsb,
948 Triangulation &triangulation,
bool verbose =
false) {
949 int tangent_space_dim = tsb.dimension();
950 const Tr_traits &local_tr_traits = triangulation.geom_traits();
953 typename K::Squared_distance_d k_sqdist = m_k.squared_distance_d_object();
956 typename Tr_traits::Compute_weight_d point_weight = local_tr_traits.compute_weight_d_object();
957 typename Tr_traits::Power_center_d power_center = local_tr_traits.power_center_d_object();
966 if (i == tsb.origin()) {
968 proj_wp = local_tr_traits.construct_weighted_point_d_object()(
969 local_tr_traits.construct_point_d_object()(tangent_space_dim, CGAL::ORIGIN), m_weights[i]);
971 const Weighted_point &wp = compute_perturbed_weighted_point(i);
972 proj_wp = project_point_and_compute_weight(wp, tsb, local_tr_traits);
975 Tr_vertex_handle center_vertex = triangulation.insert(proj_wp);
976 center_vertex->data() = i;
977 if (verbose) std::cerr <<
"* Inserted point #" << i <<
"\n";
979 #ifdef GUDHI_TC_VERY_VERBOSE 980 std::size_t num_attempts_to_insert_points = 1;
981 std::size_t num_inserted_points = 1;
985 INS_range ins_range = m_points_ds.incremental_nearest_neighbors(center_pt);
993 boost::optional<FT> squared_star_sphere_radius_plus_margin = m_max_squared_edge_length;
996 for (
auto nn_it = ins_range.begin(); nn_it != ins_range.end(); ++nn_it) {
997 std::size_t neighbor_point_idx = nn_it->first;
1000 if (neighbor_point_idx != i) {
1005 compute_perturbed_weighted_point(neighbor_point_idx, neighbor_pt, neighbor_weight);
1006 GUDHI_CHECK(!m_max_squared_edge_length ||
1007 squared_star_sphere_radius_plus_margin.value() <= m_max_squared_edge_length.value(),
1008 std::invalid_argument(
"Tangential_complex::compute_star - set a bigger value with set_max_squared_edge_length."));
1009 if (squared_star_sphere_radius_plus_margin &&
1010 k_sqdist(center_pt, neighbor_pt) > squared_star_sphere_radius_plus_margin.value()) {
1011 GUDHI_CHECK(triangulation.current_dimension() >= tangent_space_dim,
1012 std::invalid_argument(
"Tangential_complex::compute_star - Dimension of the star is only " + \
1013 std::to_string(triangulation.current_dimension())));
1017 Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb, local_tr_traits);
1019 #ifdef GUDHI_TC_VERY_VERBOSE 1020 ++num_attempts_to_insert_points;
1023 Tr_vertex_handle vh = triangulation.insert_if_in_star(proj_pt, center_vertex);
1025 if (vh != Tr_vertex_handle() && vh->data() == (std::numeric_limits<std::size_t>::max)()) {
1026 #ifdef GUDHI_TC_VERY_VERBOSE 1027 ++num_inserted_points;
1029 if (verbose) std::cerr <<
"* Inserted point #" << neighbor_point_idx <<
"\n";
1031 vh->data() = neighbor_point_idx;
1034 if (triangulation.current_dimension() >= tangent_space_dim) {
1035 squared_star_sphere_radius_plus_margin = boost::none;
1037 std::vector<Tr_full_cell_handle> incident_cells;
1038 triangulation.incident_full_cells(center_vertex, std::back_inserter(incident_cells));
1039 for (
typename std::vector<Tr_full_cell_handle>::iterator cit = incident_cells.begin();
1040 cit != incident_cells.end(); ++cit) {
1041 Tr_full_cell_handle cell = *cit;
1042 if (triangulation.is_infinite(cell)) {
1043 squared_star_sphere_radius_plus_margin = boost::none;
1049 power_center(boost::make_transform_iterator(cell->vertices_begin(),
1050 vertex_handle_to_point<Tr_point, Tr_vertex_handle>),
1051 boost::make_transform_iterator(cell->vertices_end(),
1052 vertex_handle_to_point<Tr_point, Tr_vertex_handle>));
1054 FT sq_power_sphere_diam = 4 * point_weight(c);
1056 if (!squared_star_sphere_radius_plus_margin ||
1057 sq_power_sphere_diam > squared_star_sphere_radius_plus_margin.value()) {
1058 squared_star_sphere_radius_plus_margin = sq_power_sphere_diam;
1065 if (squared_star_sphere_radius_plus_margin) {
1067 squared_star_sphere_radius_plus_margin =
1068 CGAL::square(std::sqrt(squared_star_sphere_radius_plus_margin.value()) + 2 * m_last_max_perturb);
1071 if (m_max_squared_edge_length && squared_star_sphere_radius_plus_margin.value() > m_max_squared_edge_length.value()) {
1072 squared_star_sphere_radius_plus_margin = m_max_squared_edge_length.value();
1076 m_squared_star_spheres_radii_incl_margin[i] = squared_star_sphere_radius_plus_margin.value();
1078 if (m_max_squared_edge_length) {
1079 squared_star_sphere_radius_plus_margin = m_max_squared_edge_length.value();
1080 m_squared_star_spheres_radii_incl_margin[i] = m_max_squared_edge_length.value();
1082 m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
1090 return center_vertex;
1093 void refresh_tangent_triangulation(std::size_t i, Points_ds
const &updated_pts_ds,
bool verbose =
false) {
1094 if (verbose) std::cerr <<
"** Refreshing tangent tri #" << i <<
" **\n";
1096 if (m_squared_star_spheres_radii_incl_margin[i] == FT(-1))
return compute_tangent_triangulation(i, verbose);
1098 Point center_point = compute_perturbed_point(i);
1100 std::size_t closest_pt_index = updated_pts_ds.
k_nearest_neighbors(center_point, 1,
false).begin()->first;
1102 typename K::Construct_weighted_point_d k_constr_wp = m_k.construct_weighted_point_d_object();
1103 typename K::Power_distance_d k_power_dist = m_k.power_distance_d_object();
1106 Weighted_point star_sphere = k_constr_wp(compute_perturbed_point(i), m_squared_star_spheres_radii_incl_margin[i]);
1107 Weighted_point closest_updated_point = compute_perturbed_weighted_point(closest_pt_index);
1110 if (k_power_dist(star_sphere, closest_updated_point) <= FT(0)) compute_tangent_triangulation(i, verbose);
1113 void compute_tangent_triangulation(std::size_t i,
bool verbose =
false) {
1114 if (verbose) std::cerr <<
"** Computing tangent tri #" << i <<
" **\n";
1119 const Point center_pt = compute_perturbed_point(i);
1120 Tangent_space_basis &tsb = m_tangent_spaces[i];
1123 if (!m_are_tangent_spaces_computed[i]) {
1124 #ifdef GUDHI_TC_EXPORT_NORMALS 1125 tsb = compute_tangent_space(center_pt, i,
true , &m_orth_spaces[i]);
1127 tsb = compute_tangent_space(center_pt, i);
1131 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) 1134 int tangent_space_dim = tangent_basis_dim(i);
1135 Triangulation &local_tr = m_triangulations[i].construct_triangulation(tangent_space_dim);
1137 m_triangulations[i].center_vertex() = compute_star(i, center_pt, tsb, local_tr, verbose);
1139 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) 1141 std::cerr <<
" - triangulation construction: " << t.num_seconds() <<
" s.\n";
1145 #ifdef GUDHI_TC_VERY_VERBOSE 1146 std::cerr <<
"Inserted " << num_inserted_points <<
" points / " << num_attempts_to_insert_points
1147 <<
" attemps to compute the star\n";
1152 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) 1154 std::cerr <<
" - update_star: " << t.num_seconds() <<
" s.\n";
1160 void update_star(std::size_t i) {
1161 Star &star = m_stars[i];
1163 Triangulation &local_tr = m_triangulations[i].tr();
1164 Tr_vertex_handle center_vertex = m_triangulations[i].center_vertex();
1165 int cur_dim_plus_1 = local_tr.current_dimension() + 1;
1167 std::vector<Tr_full_cell_handle> incident_cells;
1168 local_tr.incident_full_cells(center_vertex, std::back_inserter(incident_cells));
1170 typename std::vector<Tr_full_cell_handle>::const_iterator it_c = incident_cells.begin();
1171 typename std::vector<Tr_full_cell_handle>::const_iterator it_c_end = incident_cells.end();
1173 for (; it_c != it_c_end; ++it_c) {
1175 Incident_simplex incident_simplex;
1176 for (
int j = 0; j < cur_dim_plus_1; ++j) {
1177 std::size_t index = (*it_c)->vertex(j)->data();
1178 if (index != i) incident_simplex.insert(index);
1180 GUDHI_CHECK(incident_simplex.size() == cur_dim_plus_1 - 1,
1181 std::logic_error(
"update_star: wrong size of incident simplex"));
1182 star.push_back(incident_simplex);
1188 Tangent_space_basis compute_tangent_space(
const Point &p,
const std::size_t i,
bool normalize_basis =
true,
1189 Orthogonal_space_basis *p_orth_space_basis = NULL) {
1190 unsigned int num_pts_for_pca =
1191 (std::min)(static_cast<unsigned int>(std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
1192 static_cast<unsigned int>(m_points.size()));
1195 typename K::Construct_vector_d constr_vec = m_k.construct_vector_d_object();
1196 typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
1198 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM 1199 KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca,
false);
1200 const Points &points_for_pca = m_points_for_tse;
1202 KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca,
false);
1203 const Points &points_for_pca = m_points;
1207 Eigen::MatrixXd mat_points(num_pts_for_pca, m_ambient_dim);
1208 auto nn_it = kns_range.begin();
1209 for (
unsigned int j = 0; j < num_pts_for_pca && nn_it != kns_range.end(); ++j, ++nn_it) {
1210 for (
int i = 0; i < m_ambient_dim; ++i) {
1211 mat_points(j, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i));
1214 Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
1215 Eigen::MatrixXd cov = centered.adjoint() * centered;
1216 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
1218 Tangent_space_basis tsb(i);
1222 for (
int j = m_ambient_dim - 1; j >= m_ambient_dim - m_intrinsic_dim; --j) {
1223 if (normalize_basis) {
1224 Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1225 eig.eigenvectors().col(j).data() + m_ambient_dim);
1226 tsb.push_back(normalize_vector(v, m_k));
1228 tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1229 eig.eigenvectors().col(j).data() + m_ambient_dim));
1233 if (p_orth_space_basis) {
1234 p_orth_space_basis->set_origin(i);
1235 for (
int j = m_ambient_dim - m_intrinsic_dim - 1; j >= 0; --j) {
1236 if (normalize_basis) {
1237 Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1238 eig.eigenvectors().col(j).data() + m_ambient_dim);
1239 p_orth_space_basis->push_back(normalize_vector(v, m_k));
1241 p_orth_space_basis->push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1242 eig.eigenvectors().col(j).data() + m_ambient_dim));
1247 m_are_tangent_spaces_computed[i] =
true;
1257 Tangent_space_basis compute_tangent_space(
const Simplex &s,
bool normalize_basis =
true) {
1258 unsigned int num_pts_for_pca =
1259 (std::min)(static_cast<unsigned int>(std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
1260 static_cast<unsigned int>(m_points.size()));
1263 typename K::Construct_vector_d constr_vec = m_k.construct_vector_d_object();
1264 typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
1265 typename K::Squared_length_d sqlen = m_k.squared_length_d_object();
1266 typename K::Scaled_vector_d scaled_vec = m_k.scaled_vector_d_object();
1267 typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
1268 typename K::Difference_of_vectors_d diff_vec = m_k.difference_of_vectors_d_object();
1271 Eigen::MatrixXd mat_points(s.size() * num_pts_for_pca, m_ambient_dim);
1272 unsigned int current_row = 0;
1274 for (Simplex::const_iterator it_index = s.begin(); it_index != s.end(); ++it_index) {
1275 const Point &p = m_points[*it_index];
1277 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM 1278 KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca,
false);
1279 const Points &points_for_pca = m_points_for_tse;
1281 KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca,
false);
1282 const Points &points_for_pca = m_points;
1285 auto nn_it = kns_range.begin();
1286 for (; current_row < num_pts_for_pca && nn_it != kns_range.end(); ++current_row, ++nn_it) {
1287 for (
int i = 0; i < m_ambient_dim; ++i) {
1288 mat_points(current_row, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i));
1292 Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
1293 Eigen::MatrixXd cov = centered.adjoint() * centered;
1294 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
1296 Tangent_space_basis tsb;
1300 for (
int j = m_ambient_dim - 1; j >= m_ambient_dim - m_intrinsic_dim; --j) {
1301 if (normalize_basis) {
1302 Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1303 eig.eigenvectors().col(j).data() + m_ambient_dim);
1304 tsb.push_back(normalize_vector(v, m_k));
1306 tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1307 eig.eigenvectors().col(j).data() + m_ambient_dim));
1316 int tangent_basis_dim(std::size_t i)
const {
return m_tangent_spaces[i].dimension(); }
1318 Point compute_perturbed_point(std::size_t pt_idx)
const {
1319 #ifdef GUDHI_TC_PERTURB_POSITION 1320 return m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]);
1322 return m_points[pt_idx];
1326 void compute_perturbed_weighted_point(std::size_t pt_idx, Point &p, FT &w)
const {
1327 #ifdef GUDHI_TC_PERTURB_POSITION 1328 p = m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]);
1330 p = m_points[pt_idx];
1332 w = m_weights[pt_idx];
1335 Weighted_point compute_perturbed_weighted_point(std::size_t pt_idx)
const {
1336 typename K::Construct_weighted_point_d k_constr_wp = m_k.construct_weighted_point_d_object();
1338 Weighted_point wp = k_constr_wp(
1339 #ifdef GUDHI_TC_PERTURB_POSITION
1340 m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]),
1349 Point unproject_point(
const Tr_point &p,
const Tangent_space_basis &tsb,
const Tr_traits &tr_traits)
const {
1350 typename K::Translated_point_d k_transl = m_k.translated_point_d_object();
1351 typename K::Scaled_vector_d k_scaled_vec = m_k.scaled_vector_d_object();
1352 typename Tr_traits::Compute_coordinate_d coord = tr_traits.compute_coordinate_d_object();
1354 Point global_point = compute_perturbed_point(tsb.origin());
1355 for (
int i = 0; i < m_intrinsic_dim; ++i) global_point = k_transl(global_point, k_scaled_vec(tsb[i], coord(p, i)));
1357 return global_point;
1362 Tr_bare_point project_point(
const Point &p,
const Tangent_space_basis &tsb,
const Tr_traits &tr_traits)
const {
1363 typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
1364 typename K::Difference_of_points_d diff_points = m_k.difference_of_points_d_object();
1366 Vector v = diff_points(p, compute_perturbed_point(tsb.origin()));
1368 std::vector<FT> coords;
1370 coords.reserve(tsb.dimension());
1371 for (std::size_t i = 0; i < m_intrinsic_dim; ++i) {
1373 FT coord = scalar_pdct(v, tsb[i]);
1374 coords.push_back(coord);
1377 return tr_traits.construct_point_d_object()(
static_cast<int>(coords.size()), coords.begin(), coords.end());
1384 Tr_point project_point_and_compute_weight(
const Weighted_point &wp,
const Tangent_space_basis &tsb,
1385 const Tr_traits &tr_traits)
const {
1386 typename K::Point_drop_weight_d k_drop_w = m_k.point_drop_weight_d_object();
1387 typename K::Compute_weight_d k_point_weight = m_k.compute_weight_d_object();
1388 return project_point_and_compute_weight(k_drop_w(wp), k_point_weight(wp), tsb, tr_traits);
1392 Tr_point project_point_and_compute_weight(
const Point &p,
const FT w,
const Tangent_space_basis &tsb,
1393 const Tr_traits &tr_traits)
const {
1394 const int point_dim = m_k.point_dimension_d_object()(p);
1396 typename K::Construct_point_d constr_pt = m_k.construct_point_d_object();
1397 typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
1398 typename K::Difference_of_points_d diff_points = m_k.difference_of_points_d_object();
1399 typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
1400 typename K::Construct_cartesian_const_iterator_d ccci = m_k.construct_cartesian_const_iterator_d_object();
1402 Point origin = compute_perturbed_point(tsb.origin());
1403 Vector v = diff_points(p, origin);
1406 bool same_dim = (point_dim == tsb.dimension());
1408 std::vector<FT> coords;
1410 std::vector<FT> p_proj(ccci(origin), ccci(origin, 0));
1411 coords.reserve(tsb.dimension());
1412 for (
int i = 0; i < tsb.dimension(); ++i) {
1414 FT c = scalar_pdct(v, tsb[i]);
1415 coords.push_back(c);
1419 for (
int j = 0; j < point_dim; ++j) p_proj[j] += c * coord(tsb[i], j);
1424 FT sq_dist_to_proj_pt = 0;
1426 Point projected_pt = constr_pt(point_dim, p_proj.begin(), p_proj.end());
1427 sq_dist_to_proj_pt = m_k.squared_distance_d_object()(p, projected_pt);
1430 return tr_traits.construct_weighted_point_d_object()(
1431 tr_traits.construct_point_d_object()(
static_cast<int>(coords.size()), coords.begin(), coords.end()),
1432 w - sq_dist_to_proj_pt);
1437 template <
typename Indexed_po
int_range>
1438 std::vector<Tr_point> project_points_and_compute_weights(
const Indexed_point_range &point_indices,
1439 const Tangent_space_basis &tsb,
1440 const Tr_traits &tr_traits)
const {
1441 std::vector<Tr_point> ret;
1442 for (
typename Indexed_point_range::const_iterator it = point_indices.begin(), it_end = point_indices.end();
1443 it != it_end; ++it) {
1444 ret.push_back(project_point_and_compute_weight(compute_perturbed_weighted_point(*it), tsb, tr_traits));
1451 bool is_simplex_consistent(Tr_full_cell_handle fch,
int cur_dim)
const {
1453 for (
int i = 0; i < cur_dim + 1; ++i) {
1454 std::size_t data = fch->vertex(i)->data();
1457 return is_simplex_consistent(c);
1463 bool is_simplex_consistent(Simplex
const &simplex)
const {
1465 Simplex::const_iterator it_point_idx = simplex.begin();
1468 for (; it_point_idx != simplex.end(); ++it_point_idx) {
1469 std::size_t point_idx = *it_point_idx;
1471 if (point_idx == (std::numeric_limits<std::size_t>::max)())
continue;
1473 Star
const &star = m_stars[point_idx];
1476 Incident_simplex is_to_find = simplex;
1477 is_to_find.erase(point_idx);
1480 if (std::find(star.begin(), star.end(), is_to_find) == star.end())
return false;
1492 template <
typename OutputIterator>
1493 bool is_simplex_consistent(std::size_t center_point,
1494 Incident_simplex
const &s,
1495 OutputIterator points_whose_star_does_not_contain_s,
1496 bool check_also_in_non_maximal_faces =
false)
const {
1497 Simplex full_simplex = s;
1498 full_simplex.insert(center_point);
1501 Incident_simplex::const_iterator it_point_idx = s.begin();
1504 for (; it_point_idx != s.end(); ++it_point_idx) {
1505 std::size_t point_idx = *it_point_idx;
1507 if (point_idx == (std::numeric_limits<std::size_t>::max)())
continue;
1509 Star
const &star = m_stars[point_idx];
1512 Incident_simplex is_to_find = full_simplex;
1513 is_to_find.erase(point_idx);
1515 if (check_also_in_non_maximal_faces) {
1519 for (Star::const_iterator is = star.begin(), is_end = star.end(); !found && is != is_end; ++is) {
1520 if (std::includes(is->begin(), is->end(), is_to_find.begin(), is_to_find.end())) found =
true;
1523 if (!found) *points_whose_star_does_not_contain_s++ = point_idx;
1526 if (std::find(star.begin(), star.end(), is_to_find) == star.end())
1527 *points_whose_star_does_not_contain_s++ = point_idx;
1537 bool is_simplex_in_star(std::size_t p, Incident_simplex
const &s,
bool check_also_in_non_maximal_faces =
true)
const {
1538 Star
const &star = m_stars[p];
1540 if (check_also_in_non_maximal_faces) {
1544 for (Star::const_iterator is = star.begin(), is_end = star.end(); !found && is != is_end; ++is) {
1545 if (std::includes(is->begin(), is->end(), s.begin(), s.end())) found =
true;
1550 return !(std::find(star.begin(), star.end(), s) == star.end());
1554 #ifdef GUDHI_USE_TBB 1556 class Try_to_solve_inconsistencies_in_a_local_triangulation {
1558 double m_max_perturb;
1559 tbb::combinable<std::size_t> &m_num_inconsistencies;
1560 tbb::combinable<std::vector<std::size_t> > &m_updated_points;
1564 Try_to_solve_inconsistencies_in_a_local_triangulation(
Tangential_complex &tc,
double max_perturb,
1565 tbb::combinable<std::size_t> &num_inconsistencies,
1566 tbb::combinable<std::vector<std::size_t> > &updated_points)
1568 m_max_perturb(max_perturb),
1569 m_num_inconsistencies(num_inconsistencies),
1570 m_updated_points(updated_points) {}
1573 Try_to_solve_inconsistencies_in_a_local_triangulation(
1574 const Try_to_solve_inconsistencies_in_a_local_triangulation &tsilt)
1576 m_max_perturb(tsilt.m_max_perturb),
1577 m_num_inconsistencies(tsilt.m_num_inconsistencies),
1578 m_updated_points(tsilt.m_updated_points) {}
1581 void operator()(
const tbb::blocked_range<size_t> &r)
const {
1582 for (
size_t i = r.begin(); i != r.end(); ++i) {
1583 m_num_inconsistencies.local() += m_tc.try_to_solve_inconsistencies_in_a_local_triangulation(
1584 i, m_max_perturb, std::back_inserter(m_updated_points.local()));
1588 #endif // GUDHI_USE_TBB 1590 void perturb(std::size_t point_idx,
double max_perturb) {
1591 const Tr_traits &local_tr_traits = m_triangulations[point_idx].tr().geom_traits();
1592 typename Tr_traits::Compute_coordinate_d coord = local_tr_traits.compute_coordinate_d_object();
1593 typename K::Translated_point_d k_transl = m_k.translated_point_d_object();
1594 typename K::Construct_vector_d k_constr_vec = m_k.construct_vector_d_object();
1595 typename K::Scaled_vector_d k_scaled_vec = m_k.scaled_vector_d_object();
1597 CGAL::Random_points_in_ball_d<Tr_bare_point> tr_point_in_ball_generator(
1598 m_intrinsic_dim, m_random_generator.get_double(0., max_perturb));
1600 Tr_point local_random_transl =
1601 local_tr_traits.construct_weighted_point_d_object()(*tr_point_in_ball_generator++, 0);
1602 Translation_for_perturb global_transl = k_constr_vec(m_ambient_dim);
1603 const Tangent_space_basis &tsb = m_tangent_spaces[point_idx];
1604 for (
int i = 0; i < m_intrinsic_dim; ++i) {
1605 global_transl = k_transl(global_transl, k_scaled_vec(tsb[i], coord(local_random_transl, i)));
1608 #if defined(GUDHI_USE_TBB) 1609 m_p_perturb_mutexes[point_idx].lock();
1610 m_translations[point_idx] = global_transl;
1611 m_p_perturb_mutexes[point_idx].unlock();
1614 m_translations[point_idx] = global_transl;
1619 template <
typename OutputIt>
1620 bool try_to_solve_inconsistencies_in_a_local_triangulation(
1621 std::size_t tr_index,
double max_perturb, OutputIt perturbed_pts_indices = CGAL::Emptyset_iterator()) {
1622 bool is_inconsistent =
false;
1624 Star
const &star = m_stars[tr_index];
1627 Star::const_iterator it_inc_simplex = star.begin();
1628 Star::const_iterator it_inc_simplex_end = star.end();
1629 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
1630 const Incident_simplex &incident_simplex = *it_inc_simplex;
1633 if (is_infinite(incident_simplex))
continue;
1635 Simplex c = incident_simplex;
1639 if (!is_simplex_consistent(c)) {
1640 is_inconsistent =
true;
1642 std::size_t idx = tr_index;
1644 perturb(tr_index, max_perturb);
1645 *perturbed_pts_indices++ = idx;
1652 return is_inconsistent;
1657 std::ostream &export_point_set(std::ostream &os,
bool use_perturbed_points =
false,
1658 const char *coord_separator =
" ")
const {
1659 if (use_perturbed_points) {
1660 std::vector<Point> perturbed_points;
1661 perturbed_points.reserve(m_points.size());
1662 for (std::size_t i = 0; i < m_points.size(); ++i) perturbed_points.push_back(compute_perturbed_point(i));
1664 return export_point_set(m_k, perturbed_points, os, coord_separator);
1666 return export_point_set(m_k, m_points, os, coord_separator);
1670 template <
typename ProjectionFunctor = CGAL::Identity<Po
int> >
1671 std::ostream &export_vertices_to_off(std::ostream &os, std::size_t &num_vertices,
bool use_perturbed_points =
false,
1672 ProjectionFunctor
const &point_projection = ProjectionFunctor())
const {
1673 if (m_points.empty()) {
1681 const int N = (m_intrinsic_dim == 1 ? 2 : 1);
1684 typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
1686 #ifdef GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF 1687 int num_coords = m_ambient_dim;
1689 int num_coords = (std::min)(m_ambient_dim, 3);
1692 #ifdef GUDHI_TC_EXPORT_NORMALS 1693 OS_container::const_iterator it_os = m_orth_spaces.begin();
1695 typename Points::const_iterator it_p = m_points.begin();
1696 typename Points::const_iterator it_p_end = m_points.end();
1698 for (std::size_t i = 0; it_p != it_p_end; ++it_p, ++i) {
1699 Point p = point_projection(use_perturbed_points ? compute_perturbed_point(i) : *it_p);
1700 for (
int ii = 0; ii < N; ++ii) {
1702 for (; j < num_coords; ++j) os << CGAL::to_double(coord(p, j)) <<
" ";
1703 if (j == 2) os <<
"0";
1705 #ifdef GUDHI_TC_EXPORT_NORMALS 1706 for (j = 0; j < num_coords; ++j) os <<
" " << CGAL::to_double(coord(*it_os->begin(), j));
1710 #ifdef GUDHI_TC_EXPORT_NORMALS 1715 num_vertices = N * m_points.size();
1719 std::ostream &export_simplices_to_off(std::ostream &os, std::size_t &num_OFF_simplices,
1720 bool color_inconsistencies =
false,
1721 Simplex_set
const *p_simpl_to_color_in_red = NULL,
1722 Simplex_set
const *p_simpl_to_color_in_green = NULL,
1723 Simplex_set
const *p_simpl_to_color_in_blue = NULL)
const {
1726 num_OFF_simplices = 0;
1727 std::size_t num_maximal_simplices = 0;
1728 std::size_t num_inconsistent_maximal_simplices = 0;
1729 std::size_t num_inconsistent_stars = 0;
1730 typename Tr_container::const_iterator it_tr = m_triangulations.begin();
1731 typename Tr_container::const_iterator it_tr_end = m_triangulations.end();
1733 for (std::size_t idx = 0; it_tr != it_tr_end; ++it_tr, ++idx) {
1734 bool is_star_inconsistent =
false;
1736 Triangulation
const &tr = it_tr->tr();
1738 if (tr.current_dimension() < m_intrinsic_dim)
continue;
1741 std::stringstream color;
1743 color << 128 <<
" " << 128 <<
" " << 128;
1746 typedef std::vector<std::pair<Simplex, int> > Star_using_triangles;
1747 Star_using_triangles star_using_triangles;
1750 Star::const_iterator it_inc_simplex = m_stars[idx].begin();
1751 Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
1752 for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
1753 Simplex c = *it_inc_simplex;
1755 std::size_t num_vertices = c.size();
1756 ++num_maximal_simplices;
1758 int color_simplex = -1;
1759 if (color_inconsistencies && !is_simplex_consistent(c)) {
1760 ++num_inconsistent_maximal_simplices;
1762 is_star_inconsistent =
true;
1764 if (p_simpl_to_color_in_red && std::find(p_simpl_to_color_in_red->begin(), p_simpl_to_color_in_red->end(),
1765 c) != p_simpl_to_color_in_red->end()) {
1767 }
else if (p_simpl_to_color_in_green &&
1768 std::find(p_simpl_to_color_in_green->begin(), p_simpl_to_color_in_green->end(), c) !=
1769 p_simpl_to_color_in_green->end()) {
1771 }
else if (p_simpl_to_color_in_blue &&
1772 std::find(p_simpl_to_color_in_blue->begin(), p_simpl_to_color_in_blue->end(), c) !=
1773 p_simpl_to_color_in_blue->end()) {
1782 if (m_intrinsic_dim == 1) {
1784 Simplex::iterator it = c.begin();
1785 for (; it != c.end(); ++it) tmp_c.insert(*it * 2);
1786 if (num_vertices == 2) tmp_c.insert(*tmp_c.rbegin() + 1);
1791 if (num_vertices <= 3) {
1792 star_using_triangles.push_back(std::make_pair(c, color_simplex));
1795 std::vector<bool> booleans(num_vertices,
false);
1796 std::fill(booleans.begin() + num_vertices - 3, booleans.end(),
true);
1799 Simplex::iterator it = c.begin();
1800 for (
int i = 0; it != c.end(); ++i, ++it) {
1801 if (booleans[i]) triangle.insert(*it);
1803 star_using_triangles.push_back(std::make_pair(triangle, color_simplex));
1804 }
while (std::next_permutation(booleans.begin(), booleans.end()));
1809 Star_using_triangles::const_iterator it_simplex = star_using_triangles.begin();
1810 Star_using_triangles::const_iterator it_simplex_end = star_using_triangles.end();
1811 for (; it_simplex != it_simplex_end; ++it_simplex) {
1812 const Simplex &c = it_simplex->first;
1815 if (is_infinite(c))
continue;
1817 int color_simplex = it_simplex->second;
1819 std::stringstream sstr_c;
1821 Simplex::const_iterator it_point_idx = c.begin();
1822 for (; it_point_idx != c.end(); ++it_point_idx) {
1823 sstr_c << *it_point_idx <<
" ";
1826 os << 3 <<
" " << sstr_c.str();
1827 if (color_inconsistencies || p_simpl_to_color_in_red || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
1828 switch (color_simplex) {
1842 os <<
" " << color.str();
1846 ++num_OFF_simplices;
1849 if (is_star_inconsistent) ++num_inconsistent_stars;
1853 std::cerr <<
"\n==========================================================\n" 1854 <<
"Export from list of stars to OFF:\n" 1855 <<
" * Number of vertices: " << m_points.size() <<
"\n" 1856 <<
" * Total number of maximal simplices: " << num_maximal_simplices <<
"\n";
1857 if (color_inconsistencies) {
1858 std::cerr <<
" * Number of inconsistent stars: " << num_inconsistent_stars <<
" (" 1859 << (m_points.size() > 0 ? 100. * num_inconsistent_stars / m_points.size() : 0.) <<
"%)\n" 1860 <<
" * Number of inconsistent maximal simplices: " << num_inconsistent_maximal_simplices <<
" (" 1861 << (num_maximal_simplices > 0 ? 100. * num_inconsistent_maximal_simplices / num_maximal_simplices : 0.)
1864 std::cerr <<
"==========================================================\n";
1871 std::ostream &export_simplices_to_off(
const Simplicial_complex &complex, std::ostream &os,
1872 std::size_t &num_OFF_simplices,
1873 Simplex_set
const *p_simpl_to_color_in_red = NULL,
1874 Simplex_set
const *p_simpl_to_color_in_green = NULL,
1875 Simplex_set
const *p_simpl_to_color_in_blue = NULL)
const {
1876 typedef Simplicial_complex::Simplex Simplex;
1877 typedef Simplicial_complex::Simplex_set Simplex_set;
1881 num_OFF_simplices = 0;
1882 std::size_t num_maximal_simplices = 0;
1884 typename Simplex_set::const_iterator it_s = complex.simplex_range().begin();
1885 typename Simplex_set::const_iterator it_s_end = complex.simplex_range().end();
1887 for (; it_s != it_s_end; ++it_s) {
1889 ++num_maximal_simplices;
1891 int color_simplex = -1;
1892 if (p_simpl_to_color_in_red && std::find(p_simpl_to_color_in_red->begin(), p_simpl_to_color_in_red->end(), c) !=
1893 p_simpl_to_color_in_red->end()) {
1895 }
else if (p_simpl_to_color_in_green &&
1896 std::find(p_simpl_to_color_in_green->begin(), p_simpl_to_color_in_green->end(), c) !=
1897 p_simpl_to_color_in_green->end()) {
1899 }
else if (p_simpl_to_color_in_blue &&
1900 std::find(p_simpl_to_color_in_blue->begin(), p_simpl_to_color_in_blue->end(), c) !=
1901 p_simpl_to_color_in_blue->end()) {
1906 typedef std::vector<Simplex> Triangles;
1907 Triangles triangles;
1909 int num_vertices =
static_cast<int>(c.size());
1911 if (num_vertices < m_intrinsic_dim + 1)
continue;
1917 if (m_intrinsic_dim == 1) {
1919 Simplex::iterator it = c.begin();
1920 for (; it != c.end(); ++it) tmp_c.insert(*it * 2);
1921 if (num_vertices == 2) tmp_c.insert(*tmp_c.rbegin() + 1);
1926 if (num_vertices <= 3) {
1927 triangles.push_back(c);
1930 std::vector<bool> booleans(num_vertices,
false);
1931 std::fill(booleans.begin() + num_vertices - 3, booleans.end(),
true);
1934 Simplex::iterator it = c.begin();
1935 for (
int i = 0; it != c.end(); ++i, ++it) {
1936 if (booleans[i]) triangle.insert(*it);
1938 triangles.push_back(triangle);
1939 }
while (std::next_permutation(booleans.begin(), booleans.end()));
1943 Triangles::const_iterator it_tri = triangles.begin();
1944 Triangles::const_iterator it_tri_end = triangles.end();
1945 for (; it_tri != it_tri_end; ++it_tri) {
1947 if (is_infinite(*it_tri))
continue;
1950 Simplex::const_iterator it_point_idx = it_tri->begin();
1951 for (; it_point_idx != it_tri->end(); ++it_point_idx) {
1952 os << *it_point_idx <<
" ";
1955 if (p_simpl_to_color_in_red || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
1956 switch (color_simplex) {
1970 os <<
" 128 128 128";
1975 ++num_OFF_simplices;
1981 std::cerr <<
"\n==========================================================\n" 1982 <<
"Export from complex to OFF:\n" 1983 <<
" * Number of vertices: " << m_points.size() <<
"\n" 1984 <<
" * Total number of maximal simplices: " << num_maximal_simplices <<
"\n" 1985 <<
"==========================================================\n";
2002 const int m_intrinsic_dim;
2003 const int m_ambient_dim;
2007 #ifdef GUDHI_TC_PERTURB_POSITION 2008 Translations_for_perturb m_translations;
2009 #if defined(GUDHI_USE_TBB) 2010 Mutex_for_perturb *m_p_perturb_mutexes;
2014 Points_ds m_points_ds;
2015 double m_last_max_perturb;
2016 std::vector<bool> m_are_tangent_spaces_computed;
2017 TS_container m_tangent_spaces;
2018 #ifdef GUDHI_TC_EXPORT_NORMALS 2019 OS_container m_orth_spaces;
2021 Tr_container m_triangulations;
2023 Stars_container m_stars;
2024 std::vector<FT> m_squared_star_spheres_radii_incl_margin;
2025 boost::optional<FT> m_max_squared_edge_length;
2027 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM 2028 Points m_points_for_tse;
2029 Points_ds m_points_ds_for_tse;
2032 mutable CGAL::Random m_random_generator;
2038 #endif // TANGENTIAL_COMPLEX_H_
std::size_t num_inconsistent_simplices
Number of inconsistent simplices.
Definition: Tangential_complex.h:543
void set_max_squared_edge_length(FT max_squared_edge_length)
Sets the maximal possible squared edge length for the edges in the triangulations.
Definition: Tangential_complex.h:1998
Type returned by Tangential_complex::fix_inconsistencies_using_perturbation.
Definition: Tangential_complex.h:377
Point get_point(std::size_t vertex) const
Returns the point corresponding to the vertex given as parameter.
Definition: Tangential_complex.h:291
Tangential complex data structure.
Definition: Tangential_complex.h:125
Incremental_neighbor_search INS_range
The range returned by an incremental nearest or furthest neighbor search. Its value type is std::pair...
Definition: Kd_tree_search.h:111
K_neighbor_search KNS_range
The range returned by a k-nearest or k-furthest neighbor search. Its value type is std::pair<std::siz...
Definition: Kd_tree_search.h:103
KNS_range k_nearest_neighbors(Point const &p, unsigned int k, bool sorted=true, FT eps=FT(0)) const
Search for the k-nearest neighbors from a query point.
Definition: Kd_tree_search.h:175
std::size_t final_num_inconsistent_stars
final number of inconsistent stars
Definition: Tangential_complex.h:387
Definition: SimplicialComplexForAlpha.h:14
~Tangential_complex()
Destructor.
Definition: Tangential_complex.h:272
std::size_t num_simplices
Total number of simplices in stars (including duplicates that appear in several stars) ...
Definition: Tangential_complex.h:541
std::size_t best_num_inconsistent_stars
best number of inconsistent stars during the process
Definition: Tangential_complex.h:385
std::size_t num_inconsistent_stars
Number of stars containing at least one inconsistent simplex.
Definition: Tangential_complex.h:545
int create_complex(Simplex_tree_ &tree, bool export_inconsistent_simplices=true) const
Exports the complex into a Simplex_tree.
Definition: Tangential_complex.h:610
Fix_inconsistencies_info fix_inconsistencies_using_perturbation(double max_perturb, double time_limit=-1.)
Attempts to fix inconsistencies by perturbing the point positions.
Definition: Tangential_complex.h:395
std::size_t initial_num_inconsistent_stars
initial number of inconsistent stars
Definition: Tangential_complex.h:383
Tangential_complex(Point_range points, int intrinsic_dimension, const K &k=K())
Constructor from a range of points. Points are copied into the instance, and a search data structure ...
Definition: Tangential_complex.h:240
Num_inconsistencies number_of_inconsistent_simplices(bool verbose=false) const
Definition: Tangential_complex.h:551
bool success
true if all inconsistencies could be removed, false if the time limit has been reached before ...
Definition: Tangential_complex.h:379
int intrinsic_dimension() const
Returns the intrinsic dimension of the manifold.
Definition: Tangential_complex.h:279
Definition: Intro_spatial_searching.h:16
void compute_tangential_complex()
Computes the tangential complex.
Definition: Tangential_complex.h:330
int ambient_dimension() const
Returns the ambient dimension.
Definition: Tangential_complex.h:282
Type returned by Tangential_complex::number_of_inconsistent_simplices.
Definition: Tangential_complex.h:539
std::size_t number_of_vertices() const
Returns the number of vertices.
Definition: Tangential_complex.h:302
unsigned int num_steps
number of steps performed
Definition: Tangential_complex.h:381
Point get_perturbed_point(std::size_t vertex) const
Returns the perturbed position of the point corresponding to the vertex given as parameter.
Definition: Tangential_complex.h:298