Tangential_complex.h
1 /* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2  * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3  * Author(s): Clement Jamin
4  *
5  * Copyright (C) 2016 Inria
6  *
7  * Modification(s):
8  * - 2019/08 Vincent Rouvreau: Fix issue #10 for CGAL and Eigen3
9  * - YYYY/MM Author: Description of the modification
10  */
11 
12 #ifndef TANGENTIAL_COMPLEX_H_
13 #define TANGENTIAL_COMPLEX_H_
14 
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>
23 
24 #include <CGAL/Default.h>
25 #include <CGAL/Dimension.h>
26 #include <CGAL/function_objects.h> // for CGAL::Identity
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> // for CGAL_VERSION_NR
34 
35 #include <Eigen/Core>
36 #include <Eigen/Eigen>
37 #include <Eigen/src/Core/util/Macros.h> // for EIGEN_VERSION_AT_LEAST
38 
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>
45 
46 #include <tuple>
47 #include <vector>
48 #include <set>
49 #include <utility>
50 #include <sstream>
51 #include <iostream>
52 #include <limits>
53 #include <algorithm>
54 #include <functional>
55 #include <iterator>
56 #include <cmath> // for std::sqrt
57 #include <string>
58 #include <cstddef> // for std::size_t
59 
60 #ifdef GUDHI_USE_TBB
61 #include <tbb/parallel_for.h>
62 #include <tbb/combinable.h>
63 #include <mutex>
64 #endif
65 
66 // #define GUDHI_TC_EXPORT_NORMALS // Only for 3D surfaces (k=2, d=3)
67 
68 // Make compilation fail - required for external projects - https://github.com/GUDHI/gudhi-devel/issues/10
69 #if CGAL_VERSION_NR < 1041101000
70 # error Tangential_complex is only available for CGAL >= 4.11
71 #endif
72 
73 #if !EIGEN_VERSION_AT_LEAST(3,1,0)
74 # error Tangential_complex is only available for Eigen3 >= 3.1.0 installed with CGAL
75 #endif
76 
77 namespace sps = Gudhi::spatial_searching;
78 
79 namespace Gudhi {
80 
81 namespace tangential_complex {
82 
83 using namespace internal;
84 
85 class Vertex_data {
86  public:
87  Vertex_data(std::size_t data = (std::numeric_limits<std::size_t>::max)()) : m_data(data) {}
88 
89  operator std::size_t() { return m_data; }
90 
91  operator std::size_t() const { return m_data; }
92 
93  private:
94  std::size_t m_data;
95 };
96 
122 template <typename Kernel_, // ambiant kernel
123  typename DimensionTag, // intrinsic dimension
124  typename Concurrency_tag = CGAL::Parallel_tag, typename Triangulation_ = CGAL::Default>
126  typedef Kernel_ K;
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;
131 
132  typedef typename CGAL::Default::Get<
133  Triangulation_,
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> >,
139  Vertex_data>,
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;
148 
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;
153 #else
154  typedef Vector Translation_for_perturb;
155  typedef std::vector<FT> Weights;
156 #endif
157  typedef std::vector<Translation_for_perturb> Translations_for_perturb;
158 
159  // Store a local triangulation and a handle to its center vertex
160 
161  struct Tr_and_VH {
162  public:
163  Tr_and_VH() : m_tr(NULL) {}
164 
165  Tr_and_VH(int dim) : m_tr(new Triangulation(dim)) {}
166 
167  ~Tr_and_VH() { destroy_triangulation(); }
168 
169  Triangulation &construct_triangulation(int dim) {
170  delete m_tr;
171  m_tr = new Triangulation(dim);
172  return tr();
173  }
174 
175  void destroy_triangulation() {
176  delete m_tr;
177  m_tr = NULL;
178  }
179 
180  Triangulation &tr() { return *m_tr; }
181 
182  Triangulation const &tr() const { return *m_tr; }
183 
184  Tr_vertex_handle const &center_vertex() const { return m_center_vertex; }
185 
186  Tr_vertex_handle &center_vertex() { return m_center_vertex; }
187 
188  private:
189  Triangulation *m_tr;
190  Tr_vertex_handle m_center_vertex;
191  };
192 
193  public:
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;
198 
199  typedef std::vector<Point> Points;
200 
201  typedef boost::container::flat_set<std::size_t> Simplex;
202  typedef std::set<Simplex> Simplex_set;
203 
204  private:
206  typedef typename Points_ds::KNS_range KNS_range;
207  typedef typename Points_ds::INS_range INS_range;
208 
209  typedef std::vector<Tr_and_VH> Tr_container;
210  typedef std::vector<Vector> Vectors;
211 
212  // An Incident_simplex is the list of the vertex indices
213  // except the center vertex
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;
217 
218  // For transform_iterator
219 
220  static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) { return vh->point(); }
221 
222  template <typename P, typename VH>
223  static const P &vertex_handle_to_point(VH vh) {
224  return vh->point();
225  }
226 
227  public:
228  typedef internal::Simplicial_complex Simplicial_complex;
229 
239  template <typename Point_range>
240  Tangential_complex(Point_range points, int intrinsic_dimension,
241 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
242  InputIterator first_for_tse, InputIterator last_for_tse,
243 #endif
244  const K &k = K())
245  : m_k(k),
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)
251  ,
252  m_p_perturb_mutexes(NULL)
253 #endif
254  ,
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
260  ,
261  m_orth_spaces(m_points.size(), Orthogonal_space_basis())
262 #endif
263 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
264  ,
265  m_points_for_tse(first_for_tse, last_for_tse),
266  m_points_ds_for_tse(m_points_for_tse)
267 #endif
268  {
269  }
270 
273 #if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
274  delete[] m_p_perturb_mutexes;
275 #endif
276  }
277 
279  int intrinsic_dimension() const { return m_intrinsic_dim; }
280 
282  int ambient_dimension() const { return m_ambient_dim; }
283 
284  Points const &points() const { return m_points; }
285 
291  Point get_point(std::size_t vertex) const { return m_points[vertex]; }
292 
298  Point get_perturbed_point(std::size_t vertex) const { return compute_perturbed_point(vertex); }
299 
301 
302  std::size_t number_of_vertices() const { return m_points.size(); }
303 
304  void set_weights(const Weights &weights) { m_weights = weights; }
305 
306  void set_tangent_planes(const TS_container &tangent_spaces
307 #ifdef GUDHI_TC_EXPORT_NORMALS
308  ,
309  const OS_container &orthogonal_spaces
310 #endif
311  ) {
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"));
315 #else
316  GUDHI_CHECK(m_points.size() == tangent_spaces.size(), std::logic_error("Wrong sizes"));
317 #endif
318  m_tangent_spaces = tangent_spaces;
319 #ifdef GUDHI_TC_EXPORT_NORMALS
320  m_orth_spaces = orthogonal_spaces;
321 #endif
322  for (std::size_t i = 0; i < m_points.size(); ++i) m_are_tangent_spaces_computed[i] = true;
323  }
324 
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"
334  << white;
335 #endif
336 
337 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
338  Gudhi::Clock t;
339 #endif
340 
341  // We need to do that because we don't want the container to copy the
342  // already-computed triangulations (while resizing) since it would
343  // invalidate the vertex handles stored beside the triangulations
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();
350  else
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()];
355 #endif
356 #endif
357 
358 #ifdef GUDHI_USE_TBB
359  // Parallel
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));
362  } else {
363 #endif // GUDHI_USE_TBB
364  // Sequential
365  for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
366 #ifdef GUDHI_USE_TBB
367  }
368 #endif // GUDHI_USE_TBB
369 
370 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
371  t.end();
372  std::cerr << "Tangential complex computed in " << t.num_seconds() << " seconds.\n";
373 #endif
374  }
375 
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;
388  };
389 
395  Fix_inconsistencies_info fix_inconsistencies_using_perturbation(double max_perturb, double time_limit = -1.) {
397 
398  if (time_limit == 0.) return info;
399 
400  Gudhi::Clock t;
401 
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);
404 
405  if (std::get<1>(stats_before) == 0) {
406 #ifdef DEBUG_TRACES
407  std::cerr << "Nothing to fix.\n";
408 #endif
409  info.success = false;
410  return info;
411  }
412 #endif // GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
413 
414  m_last_max_perturb = max_perturb;
415 
416  bool done = false;
417  info.best_num_inconsistent_stars = m_triangulations.size();
418  info.num_steps = 0;
419  while (!done) {
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";
427 #endif
428 
429 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
430  std::cerr << yellow << "\nAttempt to fix inconsistencies using perturbations - step #" << info.num_steps + 1
431  << "... " << white;
432 #endif
433 
434  std::size_t num_inconsistent_stars = 0;
435  std::vector<std::size_t> updated_points;
436 
437 #ifdef GUDHI_TC_PROFILING
438  Gudhi::Clock t_fix_step;
439 #endif
440 
441  // Parallel
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>());
450  updated_points =
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());
456  return res;
457  });
458  } else {
459 #endif // GUDHI_USE_TBB
460  // Sequential
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));
464  }
465 #if defined(GUDHI_USE_TBB)
466  }
467 #endif // GUDHI_USE_TBB
468 
469 #ifdef GUDHI_TC_PROFILING
470  t_fix_step.end();
471 #endif
472 
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";
477 #endif
478 
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;
483 #endif
484 
485  if (num_inconsistent_stars > 0) refresh_tangential_complex(updated_points);
486 
487 #ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
488  // Confirm that all stars were actually refreshed
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;
494  else
495  std::cerr << green << "REFRESHMENT CHECK: PASSED.\n" << white;
496 #endif
497 
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);
500 
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";
507 
508  stats_before = stats_after;
509 #endif
510 
511  if (info.num_steps == 0) info.initial_num_inconsistent_stars = num_inconsistent_stars;
512 
513  if (num_inconsistent_stars < info.best_num_inconsistent_stars)
514  info.best_num_inconsistent_stars = num_inconsistent_stars;
515 
516  info.final_num_inconsistent_stars = num_inconsistent_stars;
517 
518  done = (num_inconsistent_stars == 0);
519  if (!done) {
520  ++info.num_steps;
521  if (time_limit > 0. && t.num_seconds() > time_limit) {
522 #ifdef DEBUG_TRACES
523  std::cerr << red << "Time limit reached.\n" << white;
524 #endif
525  info.success = false;
526  return info;
527  }
528  }
529  }
530 
531 #ifdef DEBUG_TRACES
532  std::cerr << green << "Fixed!\n" << white;
533 #endif
534  info.success = true;
535  return info;
536  }
537 
541  std::size_t num_simplices = 0;
543  std::size_t num_inconsistent_simplices = 0;
545  std::size_t num_inconsistent_stars = 0;
546  };
547 
550 
552 #ifdef DEBUG_TRACES
553  bool verbose = true
554 #else
555  bool verbose = false
556 #endif
557  ) const {
558  Num_inconsistencies stats;
559 
560  // For each triangulation
561  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
562  bool is_star_inconsistent = false;
563 
564  // For each cell
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) {
568  // Don't check infinite cells
569  if (is_infinite(*it_inc_simplex)) continue;
570 
571  Simplex c = *it_inc_simplex;
572  c.insert(idx); // Add the missing index
573 
574  if (!is_simplex_consistent(c)) {
576  is_star_inconsistent = true;
577  }
578 
579  ++stats.num_simplices;
580  }
581  stats.num_inconsistent_stars += is_star_inconsistent;
582  }
583 
584  if (verbose) {
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): "
589  << stats.num_inconsistent_simplices << " ("
590  << 100. * stats.num_inconsistent_simplices / stats.num_simplices << "%)\n"
591  << " * Number of stars containing inconsistent simplices: " << stats.num_inconsistent_stars << " ("
592  << 100. * stats.num_inconsistent_stars / m_points.size() << "%)\n"
593  << "==========================================================\n";
594  }
595 
596  return stats;
597  }
598 
609  template <typename Simplex_tree_>
610  int create_complex(Simplex_tree_ &tree,
611  bool export_inconsistent_simplices = true
613  ,
614  bool export_infinite_simplices = false, Simplex_set *p_inconsistent_simplices = NULL
616  ) const {
617 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
618  std::cerr << yellow << "\nExporting the TC as a Simplex_tree... " << white;
619 #endif
620 #ifdef GUDHI_TC_PROFILING
621  Gudhi::Clock t;
622 #endif
623 
624  int max_dim = -1;
625 
626  // For each triangulation
627  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
628  // For each cell of the star
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;
633 
634  // Don't export infinite cells
635  if (!export_infinite_simplices && is_infinite(c)) continue;
636 
637  if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
638  // Add the missing center vertex
639  c.insert(idx);
640 
641  if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
642 
643  // Try to insert the simplex
644  bool inserted = tree.insert_simplex_and_subfaces(c).second;
645 
646  // Inconsistent?
647  if (p_inconsistent_simplices && inserted && !is_simplex_consistent(c)) {
648  p_inconsistent_simplices->insert(c);
649  }
650  }
651  }
652 
653 #ifdef GUDHI_TC_PROFILING
654  t.end();
655  std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
656 #elif defined(DEBUG_TRACES)
657  std::cerr << yellow << "done.\n" << white;
658 #endif
659 
660  return max_dim;
661  }
662 
663  // First clears the complex then exports the TC into it
664  // Returns the max dimension of the simplices
665  // check_lower_and_higher_dim_simplices : 0 (false), 1 (true), 2 (auto)
666  // If the check is enabled, the function:
667  // - won't insert the simplex if it is already in a higher dim simplex
668  // - will erase any lower-dim simplices that are faces of the new simplex
669  // "auto" (= 2) will enable the check as a soon as it encounters a
670  // simplex whose dimension is different from the previous ones.
671  // N.B.: The check is quite expensive.
672 
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;
678 #endif
679 #ifdef GUDHI_TC_PROFILING
680  Gudhi::Clock t;
681 #endif
682 
683  int max_dim = -1;
684  complex.clear();
685 
686  // For each triangulation
687  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
688  // For each cell of the star
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;
693 
694  // Don't export infinite cells
695  if (!export_infinite_simplices && is_infinite(c)) continue;
696 
697  if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
698  // Add the missing center vertex
699  c.insert(idx);
700 
701  if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
702 
703  // Unusual simplex dim?
704  if (check_lower_and_higher_dim_simplices == 2 && max_dim != -1 && static_cast<int>(c.size()) != max_dim) {
705  // Let's activate the check
706  std::cerr << red
707  << "Info: check_lower_and_higher_dim_simplices ACTIVATED. "
708  "Export might be take some time...\n"
709  << white;
710  check_lower_and_higher_dim_simplices = 1;
711  }
712 
713  // Try to insert the simplex
714  bool added = complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1);
715 
716  // Inconsistent?
717  if (p_inconsistent_simplices && added && !is_simplex_consistent(c)) {
718  p_inconsistent_simplices->insert(c);
719  }
720  }
721  }
722 
723 #ifdef GUDHI_TC_PROFILING
724  t.end();
725  std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
726 #elif defined(DEBUG_TRACES)
727  std::cerr << yellow << "done.\n" << white;
728 #endif
729 
730  return max_dim;
731  }
732 
733  template <typename ProjectionFunctor = CGAL::Identity<Point> >
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);
741  }
742 
743  template <typename ProjectionFunctor = CGAL::Identity<Point> >
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;
751 
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";
755  return os;
756  }
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";
760  }
761 
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";
767  return os;
768  }
769 
770  std::stringstream output;
771  std::size_t num_simplices, num_vertices;
772  export_vertices_to_off(output, num_vertices, false, point_projection);
773  if (p_complex) {
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);
776  } else {
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);
779  }
780 
781 #ifdef GUDHI_TC_EXPORT_NORMALS
782  os << "N";
783 #endif
784 
785  os << "OFF \n"
786  << num_vertices << " " << num_simplices << " "
787  << "0 \n"
788  << output.str();
789 
790  return os;
791  }
792 
793  private:
794  void refresh_tangential_complex() {
795 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
796  std::cerr << yellow << "\nRefreshing TC... " << white;
797 #endif
798 
799 #ifdef GUDHI_TC_PROFILING
800  Gudhi::Clock t;
801 #endif
802 #ifdef GUDHI_USE_TBB
803  // Parallel
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));
806  } else {
807 #endif // GUDHI_USE_TBB
808  // Sequential
809  for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
810 #ifdef GUDHI_USE_TBB
811  }
812 #endif // GUDHI_USE_TBB
813 
814 #ifdef GUDHI_TC_PROFILING
815  t.end();
816  std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
817 #elif defined(DEBUG_TRACES)
818  std::cerr << yellow << "done.\n" << white;
819 #endif
820  }
821 
822  // If the list of perturbed points is provided, it is much faster
823  template <typename Point_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;
827 #endif
828 
829 #ifdef GUDHI_TC_PROFILING
830  Gudhi::Clock t;
831 #endif
832 
833  // ANN tree containing only the perturbed points
834  Points_ds updated_pts_ds(m_points, perturbed_points_indices);
835 
836 #ifdef GUDHI_USE_TBB
837  // Parallel
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));
841  } else {
842 #endif // GUDHI_USE_TBB
843  // Sequential
844  for (std::size_t i = 0; i < m_points.size(); ++i) refresh_tangent_triangulation(i, updated_pts_ds);
845 #ifdef GUDHI_USE_TBB
846  }
847 #endif // GUDHI_USE_TBB
848 
849 #ifdef GUDHI_TC_PROFILING
850  t.end();
851  std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
852 #elif defined(DEBUG_TRACES)
853  std::cerr << yellow << "done.\n" << white;
854 #endif
855  }
856 
857  void export_inconsistent_stars_to_OFF_files(std::string const &filename_base) const {
858  // For each triangulation
859  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
860  // We build a SC along the way in case it's inconsistent
861  Simplicial_complex sc;
862  // For each cell
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) {
867  // Skip infinite cells
868  if (is_infinite(*it_inc_simplex)) continue;
869 
870  Simplex c = *it_inc_simplex;
871  c.insert(idx); // Add the missing index
872 
873  sc.add_simplex(c);
874 
875  // If we do not already know this star is inconsistent, test it
876  if (!is_inconsistent && !is_simplex_consistent(c)) is_inconsistent = true;
877  }
878 
879  if (is_inconsistent) {
880  // Export star to OFF file
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);
885  }
886  }
887  }
888 
889  class Compare_distance_to_ref_point {
890  public:
891  Compare_distance_to_ref_point(Point const &ref, K const &k) : m_ref(ref), m_k(k) {}
892 
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);
896  }
897 
898  private:
899  Point const &m_ref;
900  K const &m_k;
901  };
902 
903 #ifdef GUDHI_USE_TBB
904  // Functor for compute_tangential_complex function
905  class Compute_tangent_triangulation {
906  Tangential_complex &m_tc;
907 
908  public:
909  // Constructor
910  Compute_tangent_triangulation(Tangential_complex &tc) : m_tc(tc) {}
911 
912  // Constructor
913  Compute_tangent_triangulation(const Compute_tangent_triangulation &ctt) : m_tc(ctt.m_tc) {}
914 
915  // operator()
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);
918  }
919  };
920 
921  // Functor for refresh_tangential_complex function
922  class Refresh_tangent_triangulation {
923  Tangential_complex &m_tc;
924  Points_ds const &m_updated_pts_ds;
925 
926  public:
927  // Constructor
928  Refresh_tangent_triangulation(Tangential_complex &tc, Points_ds const &updated_pts_ds)
929  : m_tc(tc), m_updated_pts_ds(updated_pts_ds) {}
930 
931  // Constructor
932  Refresh_tangent_triangulation(const Refresh_tangent_triangulation &ctt)
933  : m_tc(ctt.m_tc), m_updated_pts_ds(ctt.m_updated_pts_ds) {}
934 
935  // operator()
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);
938  }
939  };
940 #endif // GUDHI_USE_TBB
941 
942  bool is_infinite(Simplex const &s) const { return *s.rbegin() == (std::numeric_limits<std::size_t>::max)(); }
943 
944  // Output: "triangulation" is a Regular Triangulation containing at least the
945  // star of "center_pt"
946  // Returns the handle of the center vertex
947  Tr_vertex_handle compute_star(std::size_t i, const Point &center_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();
951 
952  // Kernel functor & objects
953  typename K::Squared_distance_d k_sqdist = m_k.squared_distance_d_object();
954 
955  // Triangulation's traits functor & objects
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();
958 
959  //***************************************************
960  // Build a minimal triangulation in the tangent space
961  // (we only need the star of p)
962  //***************************************************
963 
964  // Insert p
965  Tr_point proj_wp;
966  if (i == tsb.origin()) {
967  // Insert {(0, 0, 0...), m_weights[i]}
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]);
970  } else {
971  const Weighted_point &wp = compute_perturbed_weighted_point(i);
972  proj_wp = project_point_and_compute_weight(wp, tsb, local_tr_traits);
973  }
974 
975  Tr_vertex_handle center_vertex = triangulation.insert(proj_wp);
976  center_vertex->data() = i;
977  if (verbose) std::cerr << "* Inserted point #" << i << "\n";
978 
979 #ifdef GUDHI_TC_VERY_VERBOSE
980  std::size_t num_attempts_to_insert_points = 1;
981  std::size_t num_inserted_points = 1;
982 #endif
983  // const int NUM_NEIGHBORS = 150;
984  // KNS_range ins_range = m_points_ds.k_nearest_neighbors(center_pt, NUM_NEIGHBORS);
985  INS_range ins_range = m_points_ds.incremental_nearest_neighbors(center_pt);
986 
987  // While building the local triangulation, we keep the radius
988  // of the sphere "star sphere" centered at "center_vertex"
989  // and which contains all the
990  // circumspheres of the star of "center_vertex"
991  // If th the m_max_squared_edge_length is set the maximal radius of the "star sphere"
992  // is at most square root of m_max_squared_edge_length
993  boost::optional<FT> squared_star_sphere_radius_plus_margin = m_max_squared_edge_length;
994 
995  // Insert points until we find a point which is outside "star sphere"
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;
998 
999  // ith point = p, which is already inserted
1000  if (neighbor_point_idx != i) {
1001  // No need to lock the Mutex_for_perturb here since this will not be
1002  // called while other threads are perturbing the positions
1003  Point neighbor_pt;
1004  FT neighbor_weight;
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())));
1014  break;
1015  }
1016 
1017  Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb, local_tr_traits);
1018 
1019 #ifdef GUDHI_TC_VERY_VERBOSE
1020  ++num_attempts_to_insert_points;
1021 #endif
1022 
1023  Tr_vertex_handle vh = triangulation.insert_if_in_star(proj_pt, center_vertex);
1024  // Tr_vertex_handle vh = triangulation.insert(proj_pt);
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;
1028 #endif
1029  if (verbose) std::cerr << "* Inserted point #" << neighbor_point_idx << "\n";
1030 
1031  vh->data() = neighbor_point_idx;
1032 
1033  // Let's recompute squared_star_sphere_radius_plus_margin
1034  if (triangulation.current_dimension() >= tangent_space_dim) {
1035  squared_star_sphere_radius_plus_margin = boost::none;
1036  // Get the incident cells and look for the biggest circumsphere
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;
1044  break;
1045  } else {
1046  // Note that this uses the perturbed point since it uses
1047  // the points of the local triangulation
1048  Tr_point c =
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>));
1053 
1054  FT sq_power_sphere_diam = 4 * point_weight(c);
1055 
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;
1059  }
1060  }
1061  }
1062 
1063  // Let's add the margin, now
1064  // The value depends on whether we perturb weight or position
1065  if (squared_star_sphere_radius_plus_margin) {
1066  // "2*m_last_max_perturb" because both points can be perturbed
1067  squared_star_sphere_radius_plus_margin =
1068  CGAL::square(std::sqrt(squared_star_sphere_radius_plus_margin.value()) + 2 * m_last_max_perturb);
1069 
1070  // Reduce the square radius to m_max_squared_edge_length if necessary
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();
1073  }
1074 
1075  // Save it in `m_squared_star_spheres_radii_incl_margin`
1076  m_squared_star_spheres_radii_incl_margin[i] = squared_star_sphere_radius_plus_margin.value();
1077  } else {
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();
1081  } else {
1082  m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
1083  }
1084  }
1085  }
1086  }
1087  }
1088  }
1089 
1090  return center_vertex;
1091  }
1092 
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";
1095 
1096  if (m_squared_star_spheres_radii_incl_margin[i] == FT(-1)) return compute_tangent_triangulation(i, verbose);
1097 
1098  Point center_point = compute_perturbed_point(i);
1099  // Among updated point, what is the closer from our center point?
1100  std::size_t closest_pt_index = updated_pts_ds.k_nearest_neighbors(center_point, 1, false).begin()->first;
1101 
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();
1104 
1105  // Construct a weighted point equivalent to the star sphere
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);
1108 
1109  // Is the "closest point" inside our star sphere?
1110  if (k_power_dist(star_sphere, closest_updated_point) <= FT(0)) compute_tangent_triangulation(i, verbose);
1111  }
1112 
1113  void compute_tangent_triangulation(std::size_t i, bool verbose = false) {
1114  if (verbose) std::cerr << "** Computing tangent tri #" << i << " **\n";
1115  // std::cerr << "***********************************************\n";
1116 
1117  // No need to lock the mutex here since this will not be called while
1118  // other threads are perturbing the positions
1119  const Point center_pt = compute_perturbed_point(i);
1120  Tangent_space_basis &tsb = m_tangent_spaces[i];
1121 
1122  // Estimate the tangent space
1123  if (!m_are_tangent_spaces_computed[i]) {
1124 #ifdef GUDHI_TC_EXPORT_NORMALS
1125  tsb = compute_tangent_space(center_pt, i, true /*normalize*/, &m_orth_spaces[i]);
1126 #else
1127  tsb = compute_tangent_space(center_pt, i);
1128 #endif
1129  }
1130 
1131 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1132  Gudhi::Clock t;
1133 #endif
1134  int tangent_space_dim = tangent_basis_dim(i);
1135  Triangulation &local_tr = m_triangulations[i].construct_triangulation(tangent_space_dim);
1136 
1137  m_triangulations[i].center_vertex() = compute_star(i, center_pt, tsb, local_tr, verbose);
1138 
1139 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1140  t.end();
1141  std::cerr << " - triangulation construction: " << t.num_seconds() << " s.\n";
1142  t.reset();
1143 #endif
1144 
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";
1148 #endif
1149 
1150  update_star(i);
1151 
1152 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1153  t.end();
1154  std::cerr << " - update_star: " << t.num_seconds() << " s.\n";
1155 #endif
1156  }
1157 
1158  // Updates m_stars[i] directly from m_triangulations[i]
1159 
1160  void update_star(std::size_t i) {
1161  Star &star = m_stars[i];
1162  star.clear();
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;
1166 
1167  std::vector<Tr_full_cell_handle> incident_cells;
1168  local_tr.incident_full_cells(center_vertex, std::back_inserter(incident_cells));
1169 
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();
1172  // For each cell
1173  for (; it_c != it_c_end; ++it_c) {
1174  // Will contain all indices except center_vertex
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);
1179  }
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);
1183  }
1184  }
1185 
1186  // Estimates tangent subspaces using PCA
1187 
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()));
1193 
1194  // Kernel functors
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();
1197 
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;
1201 #else
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;
1204 #endif
1205 
1206  // One row = one point
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));
1212  }
1213  }
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);
1217 
1218  Tangent_space_basis tsb(i); // p = compute_perturbed_point(i) here
1219 
1220  // The eigenvectors are sorted in increasing order of their corresponding
1221  // eigenvalues
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));
1227  } else {
1228  tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1229  eig.eigenvectors().col(j).data() + m_ambient_dim));
1230  }
1231  }
1232 
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));
1240  } else {
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));
1243  }
1244  }
1245  }
1246 
1247  m_are_tangent_spaces_computed[i] = true;
1248 
1249  return tsb;
1250  }
1251 
1252  // Compute the space tangent to a simplex (p1, p2, ... pn)
1253  // TODO(CJ): Improve this?
1254  // Basically, it takes all the neighbor points to p1, p2... pn and runs PCA
1255  // on it. Note that most points are duplicated.
1256 
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()));
1261 
1262  // Kernel functors
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();
1269 
1270  // One row = one point
1271  Eigen::MatrixXd mat_points(s.size() * num_pts_for_pca, m_ambient_dim);
1272  unsigned int current_row = 0;
1273 
1274  for (Simplex::const_iterator it_index = s.begin(); it_index != s.end(); ++it_index) {
1275  const Point &p = m_points[*it_index];
1276 
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;
1280 #else
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;
1283 #endif
1284 
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));
1289  }
1290  }
1291  }
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);
1295 
1296  Tangent_space_basis tsb;
1297 
1298  // The eigenvectors are sorted in increasing order of their corresponding
1299  // eigenvalues
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));
1305  } else {
1306  tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
1307  eig.eigenvectors().col(j).data() + m_ambient_dim));
1308  }
1309  }
1310 
1311  return tsb;
1312  }
1313 
1314  // Returns the dimension of the ith local triangulation
1315 
1316  int tangent_basis_dim(std::size_t i) const { return m_tangent_spaces[i].dimension(); }
1317 
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]);
1321 #else
1322  return m_points[pt_idx];
1323 #endif
1324  }
1325 
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]);
1329 #else
1330  p = m_points[pt_idx];
1331 #endif
1332  w = m_weights[pt_idx];
1333  }
1334 
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();
1337 
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]),
1341 #else
1342  m_points[pt_idx],
1343 #endif
1344  m_weights[pt_idx]);
1345 
1346  return wp;
1347  }
1348 
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();
1353 
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)));
1356 
1357  return global_point;
1358  }
1359 
1360  // Project the point in the tangent space
1361  // Resulting point coords are expressed in tsb's space
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();
1365 
1366  Vector v = diff_points(p, compute_perturbed_point(tsb.origin()));
1367 
1368  std::vector<FT> coords;
1369  // Ambiant-space coords of the projected point
1370  coords.reserve(tsb.dimension());
1371  for (std::size_t i = 0; i < m_intrinsic_dim; ++i) {
1372  // Local coords are given by the scalar product with the vectors of tsb
1373  FT coord = scalar_pdct(v, tsb[i]);
1374  coords.push_back(coord);
1375  }
1376 
1377  return tr_traits.construct_point_d_object()(static_cast<int>(coords.size()), coords.begin(), coords.end());
1378  }
1379 
1380  // Project the point in the tangent space
1381  // The weight will be the squared distance between p and the projection of p
1382  // Resulting point coords are expressed in tsb's space
1383 
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);
1389  }
1390 
1391  // Same as above, with slightly different parameters
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);
1395 
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();
1401 
1402  Point origin = compute_perturbed_point(tsb.origin());
1403  Vector v = diff_points(p, origin);
1404 
1405  // Same dimension? Then the weight is 0
1406  bool same_dim = (point_dim == tsb.dimension());
1407 
1408  std::vector<FT> coords;
1409  // Ambiant-space coords of the projected point
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) {
1413  // Local coords are given by the scalar product with the vectors of tsb
1414  FT c = scalar_pdct(v, tsb[i]);
1415  coords.push_back(c);
1416 
1417  // p_proj += c * tsb[i]
1418  if (!same_dim) {
1419  for (int j = 0; j < point_dim; ++j) p_proj[j] += c * coord(tsb[i], j);
1420  }
1421  }
1422 
1423  // Same dimension? Then the weight is 0
1424  FT sq_dist_to_proj_pt = 0;
1425  if (!same_dim) {
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);
1428  }
1429 
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);
1433  }
1434 
1435  // Project all the points in the tangent space
1436 
1437  template <typename Indexed_point_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));
1445  }
1446  return ret;
1447  }
1448 
1449  // A simplex here is a local tri's full cell handle
1450 
1451  bool is_simplex_consistent(Tr_full_cell_handle fch, int cur_dim) const {
1452  Simplex c;
1453  for (int i = 0; i < cur_dim + 1; ++i) {
1454  std::size_t data = fch->vertex(i)->data();
1455  c.insert(data);
1456  }
1457  return is_simplex_consistent(c);
1458  }
1459 
1460  // A simplex here is a list of point indices
1461  // TODO(CJ): improve it like the other "is_simplex_consistent" below
1462 
1463  bool is_simplex_consistent(Simplex const &simplex) const {
1464  // Check if the simplex is in the stars of all its vertices
1465  Simplex::const_iterator it_point_idx = simplex.begin();
1466  // For each point p of the simplex, we parse the incidents cells of p
1467  // and we check if "simplex" is among them
1468  for (; it_point_idx != simplex.end(); ++it_point_idx) {
1469  std::size_t point_idx = *it_point_idx;
1470  // Don't check infinite simplices
1471  if (point_idx == (std::numeric_limits<std::size_t>::max)()) continue;
1472 
1473  Star const &star = m_stars[point_idx];
1474 
1475  // What we're looking for is "simplex" \ point_idx
1476  Incident_simplex is_to_find = simplex;
1477  is_to_find.erase(point_idx);
1478 
1479  // For each cell
1480  if (std::find(star.begin(), star.end(), is_to_find) == star.end()) return false;
1481  }
1482 
1483  return true;
1484  }
1485 
1486  // A simplex here is a list of point indices
1487  // "s" contains all the points of the simplex except "center_point"
1488  // This function returns the points whose star doesn't contain the simplex
1489  // N.B.: the function assumes that the simplex is contained in
1490  // star(center_point)
1491 
1492  template <typename OutputIterator> // value_type = std::size_t
1493  bool is_simplex_consistent(std::size_t center_point,
1494  Incident_simplex const &s, // without "center_point"
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);
1499 
1500  // Check if the simplex is in the stars of all its vertices
1501  Incident_simplex::const_iterator it_point_idx = s.begin();
1502  // For each point p of the simplex, we parse the incidents cells of p
1503  // and we check if "simplex" is among them
1504  for (; it_point_idx != s.end(); ++it_point_idx) {
1505  std::size_t point_idx = *it_point_idx;
1506  // Don't check infinite simplices
1507  if (point_idx == (std::numeric_limits<std::size_t>::max)()) continue;
1508 
1509  Star const &star = m_stars[point_idx];
1510 
1511  // What we're looking for is full_simplex \ point_idx
1512  Incident_simplex is_to_find = full_simplex;
1513  is_to_find.erase(point_idx);
1514 
1515  if (check_also_in_non_maximal_faces) {
1516  // For each simplex "is" of the star, check if ic_to_simplex is
1517  // included in "is"
1518  bool found = false;
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;
1521  }
1522 
1523  if (!found) *points_whose_star_does_not_contain_s++ = point_idx;
1524  } else {
1525  // Does the star contain is_to_find?
1526  if (std::find(star.begin(), star.end(), is_to_find) == star.end())
1527  *points_whose_star_does_not_contain_s++ = point_idx;
1528  }
1529  }
1530 
1531  return true;
1532  }
1533 
1534  // A simplex here is a list of point indices
1535  // It looks for s in star(p).
1536  // "s" contains all the points of the simplex except p.
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];
1539 
1540  if (check_also_in_non_maximal_faces) {
1541  // For each simplex "is" of the star, check if ic_to_simplex is
1542  // included in "is"
1543  bool found = false;
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;
1546  }
1547 
1548  return found;
1549  } else {
1550  return !(std::find(star.begin(), star.end(), s) == star.end());
1551  }
1552  }
1553 
1554 #ifdef GUDHI_USE_TBB
1555  // Functor for try_to_solve_inconsistencies_in_a_local_triangulation function
1556  class Try_to_solve_inconsistencies_in_a_local_triangulation {
1557  Tangential_complex &m_tc;
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;
1561 
1562  public:
1563  // Constructor
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)
1567  : m_tc(tc),
1568  m_max_perturb(max_perturb),
1569  m_num_inconsistencies(num_inconsistencies),
1570  m_updated_points(updated_points) {}
1571 
1572  // Constructor
1573  Try_to_solve_inconsistencies_in_a_local_triangulation(
1574  const Try_to_solve_inconsistencies_in_a_local_triangulation &tsilt)
1575  : m_tc(tsilt.m_tc),
1576  m_max_perturb(tsilt.m_max_perturb),
1577  m_num_inconsistencies(tsilt.m_num_inconsistencies),
1578  m_updated_points(tsilt.m_updated_points) {}
1579 
1580  // operator()
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()));
1585  }
1586  }
1587  };
1588 #endif // GUDHI_USE_TBB
1589 
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();
1596 
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));
1599 
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)));
1606  }
1607  // Parallel
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();
1612  // Sequential
1613 #else
1614  m_translations[point_idx] = global_transl;
1615 #endif
1616  }
1617 
1618  // Return true if inconsistencies were found
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;
1623 
1624  Star const &star = m_stars[tr_index];
1625 
1626  // For each incident simplex
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;
1631 
1632  // Don't check infinite cells
1633  if (is_infinite(incident_simplex)) continue;
1634 
1635  Simplex c = incident_simplex;
1636  c.insert(tr_index); // Add the missing index
1637 
1638  // Perturb the center point
1639  if (!is_simplex_consistent(c)) {
1640  is_inconsistent = true;
1641 
1642  std::size_t idx = tr_index;
1643 
1644  perturb(tr_index, max_perturb);
1645  *perturbed_pts_indices++ = idx;
1646 
1647  // We will try the other cells next time
1648  break;
1649  }
1650  }
1651 
1652  return is_inconsistent;
1653  }
1654 
1655  // 1st line: number of points
1656  // Then one point per line
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));
1663 
1664  return export_point_set(m_k, perturbed_points, os, coord_separator);
1665  } else {
1666  return export_point_set(m_k, m_points, os, coord_separator);
1667  }
1668  }
1669 
1670  template <typename ProjectionFunctor = CGAL::Identity<Point> >
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()) {
1674  num_vertices = 0;
1675  return os;
1676  }
1677 
1678  // If m_intrinsic_dim = 1, we output each point two times
1679  // to be able to export each segment as a flat triangle with 3 different
1680  // indices (otherwise, Meshlab detects degenerated simplices)
1681  const int N = (m_intrinsic_dim == 1 ? 2 : 1);
1682 
1683  // Kernel functors
1684  typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
1685 
1686 #ifdef GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF
1687  int num_coords = m_ambient_dim;
1688 #else
1689  int num_coords = (std::min)(m_ambient_dim, 3);
1690 #endif
1691 
1692 #ifdef GUDHI_TC_EXPORT_NORMALS
1693  OS_container::const_iterator it_os = m_orth_spaces.begin();
1694 #endif
1695  typename Points::const_iterator it_p = m_points.begin();
1696  typename Points::const_iterator it_p_end = m_points.end();
1697  // For each point p
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) {
1701  int j = 0;
1702  for (; j < num_coords; ++j) os << CGAL::to_double(coord(p, j)) << " ";
1703  if (j == 2) os << "0";
1704 
1705 #ifdef GUDHI_TC_EXPORT_NORMALS
1706  for (j = 0; j < num_coords; ++j) os << " " << CGAL::to_double(coord(*it_os->begin(), j));
1707 #endif
1708  os << "\n";
1709  }
1710 #ifdef GUDHI_TC_EXPORT_NORMALS
1711  ++it_os;
1712 #endif
1713  }
1714 
1715  num_vertices = N * m_points.size();
1716  return os;
1717  }
1718 
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 {
1724  // If m_intrinsic_dim = 1, each point is output two times
1725  // (see export_vertices_to_off)
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();
1732  // For each triangulation
1733  for (std::size_t idx = 0; it_tr != it_tr_end; ++it_tr, ++idx) {
1734  bool is_star_inconsistent = false;
1735 
1736  Triangulation const &tr = it_tr->tr();
1737 
1738  if (tr.current_dimension() < m_intrinsic_dim) continue;
1739 
1740  // Color for this star
1741  std::stringstream color;
1742  // color << rand()%256 << " " << 100+rand()%156 << " " << 100+rand()%156;
1743  color << 128 << " " << 128 << " " << 128;
1744 
1745  // Gather the triangles here, with an int telling its color
1746  typedef std::vector<std::pair<Simplex, int> > Star_using_triangles;
1747  Star_using_triangles star_using_triangles;
1748 
1749  // For each cell of the star
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;
1754  c.insert(idx);
1755  std::size_t num_vertices = c.size();
1756  ++num_maximal_simplices;
1757 
1758  int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
1759  if (color_inconsistencies && !is_simplex_consistent(c)) {
1760  ++num_inconsistent_maximal_simplices;
1761  color_simplex = 0;
1762  is_star_inconsistent = true;
1763  } else {
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()) {
1766  color_simplex = 1;
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()) {
1770  color_simplex = 2;
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()) {
1774  color_simplex = 3;
1775  }
1776  }
1777 
1778  // If m_intrinsic_dim = 1, each point is output two times,
1779  // so we need to multiply each index by 2
1780  // And if only 2 vertices, add a third one (each vertex is duplicated in
1781  // the file when m_intrinsic dim = 2)
1782  if (m_intrinsic_dim == 1) {
1783  Simplex tmp_c;
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);
1787 
1788  c = tmp_c;
1789  }
1790 
1791  if (num_vertices <= 3) {
1792  star_using_triangles.push_back(std::make_pair(c, color_simplex));
1793  } else {
1794  // num_vertices >= 4: decompose the simplex in triangles
1795  std::vector<bool> booleans(num_vertices, false);
1796  std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
1797  do {
1798  Simplex triangle;
1799  Simplex::iterator it = c.begin();
1800  for (int i = 0; it != c.end(); ++i, ++it) {
1801  if (booleans[i]) triangle.insert(*it);
1802  }
1803  star_using_triangles.push_back(std::make_pair(triangle, color_simplex));
1804  } while (std::next_permutation(booleans.begin(), booleans.end()));
1805  }
1806  }
1807 
1808  // For each cell
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;
1813 
1814  // Don't export infinite cells
1815  if (is_infinite(c)) continue;
1816 
1817  int color_simplex = it_simplex->second;
1818 
1819  std::stringstream sstr_c;
1820 
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 << " ";
1824  }
1825 
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) {
1829  case 0:
1830  os << " 255 255 0";
1831  break;
1832  case 1:
1833  os << " 255 0 0";
1834  break;
1835  case 2:
1836  os << " 0 255 0";
1837  break;
1838  case 3:
1839  os << " 0 0 255";
1840  break;
1841  default:
1842  os << " " << color.str();
1843  break;
1844  }
1845  }
1846  ++num_OFF_simplices;
1847  os << "\n";
1848  }
1849  if (is_star_inconsistent) ++num_inconsistent_stars;
1850  }
1851 
1852 #ifdef DEBUG_TRACES
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.)
1862  << "%)\n";
1863  }
1864  std::cerr << "==========================================================\n";
1865 #endif
1866 
1867  return os;
1868  }
1869 
1870  public:
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;
1878 
1879  // If m_intrinsic_dim = 1, each point is output two times
1880  // (see export_vertices_to_off)
1881  num_OFF_simplices = 0;
1882  std::size_t num_maximal_simplices = 0;
1883 
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();
1886  // For each simplex
1887  for (; it_s != it_s_end; ++it_s) {
1888  Simplex c = *it_s;
1889  ++num_maximal_simplices;
1890 
1891  int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
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()) {
1894  color_simplex = 1;
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()) {
1898  color_simplex = 2;
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()) {
1902  color_simplex = 3;
1903  }
1904 
1905  // Gather the triangles here
1906  typedef std::vector<Simplex> Triangles;
1907  Triangles triangles;
1908 
1909  int num_vertices = static_cast<int>(c.size());
1910  // Do not export smaller dimension simplices
1911  if (num_vertices < m_intrinsic_dim + 1) continue;
1912 
1913  // If m_intrinsic_dim = 1, each point is output two times,
1914  // so we need to multiply each index by 2
1915  // And if only 2 vertices, add a third one (each vertex is duplicated in
1916  // the file when m_intrinsic dim = 2)
1917  if (m_intrinsic_dim == 1) {
1918  Simplex tmp_c;
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);
1922 
1923  c = tmp_c;
1924  }
1925 
1926  if (num_vertices <= 3) {
1927  triangles.push_back(c);
1928  } else {
1929  // num_vertices >= 4: decompose the simplex in triangles
1930  std::vector<bool> booleans(num_vertices, false);
1931  std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
1932  do {
1933  Simplex triangle;
1934  Simplex::iterator it = c.begin();
1935  for (int i = 0; it != c.end(); ++i, ++it) {
1936  if (booleans[i]) triangle.insert(*it);
1937  }
1938  triangles.push_back(triangle);
1939  } while (std::next_permutation(booleans.begin(), booleans.end()));
1940  }
1941 
1942  // For each cell
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) {
1946  // Don't export infinite cells
1947  if (is_infinite(*it_tri)) continue;
1948 
1949  os << 3 << " ";
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 << " ";
1953  }
1954 
1955  if (p_simpl_to_color_in_red || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
1956  switch (color_simplex) {
1957  case 0:
1958  os << " 255 255 0";
1959  break;
1960  case 1:
1961  os << " 255 0 0";
1962  break;
1963  case 2:
1964  os << " 0 255 0";
1965  break;
1966  case 3:
1967  os << " 0 0 255";
1968  break;
1969  default:
1970  os << " 128 128 128";
1971  break;
1972  }
1973  }
1974 
1975  ++num_OFF_simplices;
1976  os << "\n";
1977  }
1978  }
1979 
1980 #ifdef DEBUG_TRACES
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";
1986 #endif
1987 
1988  return os;
1989  }
1990 
1998  void set_max_squared_edge_length(FT max_squared_edge_length) { m_max_squared_edge_length = max_squared_edge_length; }
1999 
2000  private:
2001  const K m_k;
2002  const int m_intrinsic_dim;
2003  const int m_ambient_dim;
2004 
2005  Points m_points;
2006  Weights m_weights;
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;
2011 #endif
2012 #endif
2013 
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;
2020 #endif
2021  Tr_container m_triangulations; // Contains the triangulations
2022  // and their center vertex
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;
2026 
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;
2030 #endif
2031 
2032  mutable CGAL::Random m_random_generator;
2033 }; // /class Tangential_complex
2034 
2035 } // end namespace tangential_complex
2036 } // end namespace Gudhi
2037 
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
GUDHI  Version 3.3.0  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : MIT Generated on Tue Aug 11 2020 11:09:13 for GUDHI by Doxygen 1.8.13