Tangential_complex.h
1 /* This file is part of the Gudhi Library. The Gudhi library
2  * (Geometric Understanding in Higher Dimensions) is a generic C++
3  * library for computational topology.
4  *
5  * Author(s): Clement Jamin
6  *
7  * Copyright (C) 2016 Inria
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifndef TANGENTIAL_COMPLEX_H_
24 #define TANGENTIAL_COMPLEX_H_
25 
26 #include <gudhi/Tangential_complex/config.h>
27 #include <gudhi/Tangential_complex/Simplicial_complex.h>
28 #include <gudhi/Tangential_complex/utilities.h>
29 #include <gudhi/Kd_tree_search.h>
30 #include <gudhi/console_color.h>
31 #include <gudhi/Clock.h>
32 #include <gudhi/Simplex_tree.h>
33 
34 #include <CGAL/Default.h>
35 #include <CGAL/Dimension.h>
36 #include <CGAL/function_objects.h> // for CGAL::Identity
37 #include <CGAL/Epick_d.h>
38 #include <CGAL/Regular_triangulation_traits_adapter.h>
39 #include <CGAL/Regular_triangulation.h>
40 #include <CGAL/Delaunay_triangulation.h>
41 #include <CGAL/Combination_enumerator.h>
42 #include <CGAL/point_generators_d.h>
43 
44 #include <Eigen/Core>
45 #include <Eigen/Eigen>
46 
47 #include <boost/optional.hpp>
48 #include <boost/iterator/transform_iterator.hpp>
49 #include <boost/range/adaptor/transformed.hpp>
50 #include <boost/range/counting_range.hpp>
51 #include <boost/math/special_functions/factorials.hpp>
52 #include <boost/container/flat_set.hpp>
53 
54 #include <tuple>
55 #include <vector>
56 #include <set>
57 #include <utility>
58 #include <sstream>
59 #include <iostream>
60 #include <limits>
61 #include <algorithm>
62 #include <functional>
63 #include <iterator>
64 #include <cmath> // for std::sqrt
65 #include <string>
66 #include <cstddef> // for std::size_t
67 
68 #ifdef GUDHI_USE_TBB
69 #include <tbb/parallel_for.h>
70 #include <tbb/combinable.h>
71 #include <tbb/mutex.h>
72 #endif
73 
74 // #define GUDHI_TC_EXPORT_NORMALS // Only for 3D surfaces (k=2, d=3)
75 
76 namespace sps = Gudhi::spatial_searching;
77 
78 namespace Gudhi {
79 
80 namespace tangential_complex {
81 
82 using namespace internal;
83 
84 class Vertex_data {
85  public:
86  Vertex_data(std::size_t data = (std::numeric_limits<std::size_t>::max)())
87  : m_data(data) { }
88 
89  operator std::size_t() {
90  return m_data;
91  }
92 
93  operator std::size_t() const {
94  return m_data;
95  }
96 
97  private:
98  std::size_t m_data;
99 };
100 
125 template
126 <
127  typename Kernel_, // ambiant kernel
128  typename DimensionTag, // intrinsic dimension
129  typename Concurrency_tag = CGAL::Parallel_tag,
130  typename Triangulation_ = CGAL::Default
131 >
133  typedef Kernel_ K;
134  typedef typename K::FT FT;
135  typedef typename K::Point_d Point;
136  typedef typename K::Weighted_point_d Weighted_point;
137  typedef typename K::Vector_d Vector;
138 
139  typedef typename CGAL::Default::Get
140  <
141  Triangulation_,
142  CGAL::Regular_triangulation
143  <
144  CGAL::Epick_d<DimensionTag>,
145  CGAL::Triangulation_data_structure
146  <
147  typename CGAL::Epick_d<DimensionTag>::Dimension,
148  CGAL::Triangulation_vertex
149  <
150  CGAL::Regular_triangulation_traits_adapter< CGAL::Epick_d<DimensionTag> >, Vertex_data
151  >,
152  CGAL::Triangulation_full_cell<CGAL::Regular_triangulation_traits_adapter< CGAL::Epick_d<DimensionTag> > >
153  >
154  >
155  >::type Triangulation;
156  typedef typename Triangulation::Geom_traits Tr_traits;
157  typedef typename Triangulation::Weighted_point Tr_point;
158  typedef typename Tr_traits::Base::Point_d Tr_bare_point;
159  typedef typename Triangulation::Vertex_handle Tr_vertex_handle;
160  typedef typename Triangulation::Full_cell_handle Tr_full_cell_handle;
161  typedef typename Tr_traits::Vector_d Tr_vector;
162 
163 #if defined(GUDHI_USE_TBB)
164  typedef tbb::mutex Mutex_for_perturb;
165  typedef Vector Translation_for_perturb;
166  typedef std::vector<Atomic_wrapper<FT> > Weights;
167 #else
168  typedef Vector Translation_for_perturb;
169  typedef std::vector<FT> Weights;
170 #endif
171  typedef std::vector<Translation_for_perturb> Translations_for_perturb;
172 
173  // Store a local triangulation and a handle to its center vertex
174 
175  struct Tr_and_VH {
176  public:
177  Tr_and_VH()
178  : m_tr(NULL) { }
179 
180  Tr_and_VH(int dim)
181  : m_tr(new Triangulation(dim)) { }
182 
183  ~Tr_and_VH() {
184  destroy_triangulation();
185  }
186 
187  Triangulation & construct_triangulation(int dim) {
188  delete m_tr;
189  m_tr = new Triangulation(dim);
190  return tr();
191  }
192 
193  void destroy_triangulation() {
194  delete m_tr;
195  m_tr = NULL;
196  }
197 
198  Triangulation & tr() {
199  return *m_tr;
200  }
201 
202  Triangulation const& tr() const {
203  return *m_tr;
204  }
205 
206  Tr_vertex_handle const& center_vertex() const {
207  return m_center_vertex;
208  }
209 
210  Tr_vertex_handle & center_vertex() {
211  return m_center_vertex;
212  }
213 
214  private:
215  Triangulation* m_tr;
216  Tr_vertex_handle m_center_vertex;
217  };
218 
219  public:
220  typedef Basis<K> Tangent_space_basis;
221  typedef Basis<K> Orthogonal_space_basis;
222  typedef std::vector<Tangent_space_basis> TS_container;
223  typedef std::vector<Orthogonal_space_basis> OS_container;
224 
225  typedef std::vector<Point> Points;
226 
227  typedef boost::container::flat_set<std::size_t> Simplex;
228  typedef std::set<Simplex> Simplex_set;
229 
230  private:
232  typedef typename Points_ds::KNS_range KNS_range;
233  typedef typename Points_ds::INS_range INS_range;
234 
235  typedef std::vector<Tr_and_VH> Tr_container;
236  typedef std::vector<Vector> Vectors;
237 
238  // An Incident_simplex is the list of the vertex indices
239  // except the center vertex
240  typedef boost::container::flat_set<std::size_t> Incident_simplex;
241  typedef std::vector<Incident_simplex> Star;
242  typedef std::vector<Star> Stars_container;
243 
244  // For transform_iterator
245 
246  static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) {
247  return vh->point();
248  }
249 
250  template <typename P, typename VH>
251  static const P &vertex_handle_to_point(VH vh) {
252  return vh->point();
253  }
254 
255  public:
256  typedef internal::Simplicial_complex Simplicial_complex;
257 
267  template <typename Point_range>
268  Tangential_complex(Point_range points,
269  int intrinsic_dimension,
270 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
271  InputIterator first_for_tse, InputIterator last_for_tse,
272 #endif
273  const K &k = K()
274  )
275  : m_k(k),
276  m_intrinsic_dim(intrinsic_dimension),
277  m_ambient_dim(points.empty() ? 0 : k.point_dimension_d_object()(*points.begin())),
278  m_points(points.begin(), points.end()),
279  m_weights(m_points.size(), FT(0))
280 #if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
281  , m_p_perturb_mutexes(NULL)
282 #endif
283  , m_points_ds(m_points)
284  , m_last_max_perturb(0.)
285  , m_are_tangent_spaces_computed(m_points.size(), false)
286  , m_tangent_spaces(m_points.size(), Tangent_space_basis())
287 #ifdef GUDHI_TC_EXPORT_NORMALS
288  , m_orth_spaces(m_points.size(), Orthogonal_space_basis())
289 #endif
290 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
291  , m_points_for_tse(first_for_tse, last_for_tse)
292  , m_points_ds_for_tse(m_points_for_tse)
293 #endif
294  { }
295 
298 #if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
299  delete [] m_p_perturb_mutexes;
300 #endif
301  }
302 
304  int intrinsic_dimension() const {
305  return m_intrinsic_dim;
306  }
307 
309  int ambient_dimension() const {
310  return m_ambient_dim;
311  }
312 
313  Points const& points() const {
314  return m_points;
315  }
316 
322  Point get_point(std::size_t vertex) const {
323  return m_points[vertex];
324  }
325 
331  Point get_perturbed_point(std::size_t vertex) const {
332  return compute_perturbed_point(vertex);
333  }
334 
336 
337  std::size_t number_of_vertices() const {
338  return m_points.size();
339  }
340 
341  void set_weights(const Weights& weights) {
342  m_weights = weights;
343  }
344 
345  void set_tangent_planes(const TS_container& tangent_spaces
346 #ifdef GUDHI_TC_EXPORT_NORMALS
347  , const OS_container& orthogonal_spaces
348 #endif
349  ) {
350 #ifdef GUDHI_TC_EXPORT_NORMALS
351  GUDHI_CHECK(
352  m_points.size() == tangent_spaces.size()
353  && m_points.size() == orthogonal_spaces.size(),
354  std::logic_error("Wrong sizes"));
355 #else
356  GUDHI_CHECK(
357  m_points.size() == tangent_spaces.size(),
358  std::logic_error("Wrong sizes"));
359 #endif
360  m_tangent_spaces = tangent_spaces;
361 #ifdef GUDHI_TC_EXPORT_NORMALS
362  m_orth_spaces = orthogonal_spaces;
363 #endif
364  for (std::size_t i = 0; i < m_points.size(); ++i)
365  m_are_tangent_spaces_computed[i] = true;
366  }
367 
370 #ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
371  std::cerr << red << "WARNING: GUDHI_TC_PERFORM_EXTRA_CHECKS is defined. "
372  << "Computation might be slower than usual.\n" << white;
373 #endif
374 
375 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
376  Gudhi::Clock t;
377 #endif
378 
379  // We need to do that because we don't want the container to copy the
380  // already-computed triangulations (while resizing) since it would
381  // invalidate the vertex handles stored beside the triangulations
382  m_triangulations.resize(m_points.size());
383  m_stars.resize(m_points.size());
384  m_squared_star_spheres_radii_incl_margin.resize(m_points.size(), FT(-1));
385 #ifdef GUDHI_TC_PERTURB_POSITION
386  if (m_points.empty())
387  m_translations.clear();
388  else
389  m_translations.resize(m_points.size(),
390  m_k.construct_vector_d_object()(m_ambient_dim));
391 #if defined(GUDHI_USE_TBB)
392  delete [] m_p_perturb_mutexes;
393  m_p_perturb_mutexes = new Mutex_for_perturb[m_points.size()];
394 #endif
395 #endif
396 
397 #ifdef GUDHI_USE_TBB
398  // Parallel
399  if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
400  tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()),
401  Compute_tangent_triangulation(*this));
402  } else {
403 #endif // GUDHI_USE_TBB
404  // Sequential
405  for (std::size_t i = 0; i < m_points.size(); ++i)
406  compute_tangent_triangulation(i);
407 #ifdef GUDHI_USE_TBB
408  }
409 #endif // GUDHI_USE_TBB
410 
411 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
412  t.end();
413  std::cerr << "Tangential complex computed in " << t.num_seconds()
414  << " seconds.\n";
415 #endif
416  }
417 
421  bool success = false;
423  unsigned int num_steps = 0;
425  std::size_t initial_num_inconsistent_stars = 0;
427  std::size_t best_num_inconsistent_stars = 0;
429  std::size_t final_num_inconsistent_stars = 0;
430  };
431 
437  Fix_inconsistencies_info fix_inconsistencies_using_perturbation(double max_perturb, double time_limit = -1.) {
439 
440  if (time_limit == 0.)
441  return info;
442 
443  Gudhi::Clock t;
444 
445 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
446  std::tuple<std::size_t, std::size_t, std::size_t> stats_before =
447  number_of_inconsistent_simplices(false);
448 
449  if (std::get<1>(stats_before) == 0) {
450 #ifdef DEBUG_TRACES
451  std::cerr << "Nothing to fix.\n";
452 #endif
453  info.success = false;
454  return info;
455  }
456 #endif // GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
457 
458  m_last_max_perturb = max_perturb;
459 
460  bool done = false;
461  info.best_num_inconsistent_stars = m_triangulations.size();
462  info.num_steps = 0;
463  while (!done) {
464 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
465  std::cerr
466  << "\nBefore fix step:\n"
467  << " * Total number of simplices in stars (incl. duplicates): "
468  << std::get<0>(stats_before) << "\n"
469  << " * Num inconsistent simplices in stars (incl. duplicates): "
470  << red << std::get<1>(stats_before) << white << " ("
471  << 100. * std::get<1>(stats_before) / std::get<0>(stats_before) << "%)\n"
472  << " * Number of stars containing inconsistent simplices: "
473  << red << std::get<2>(stats_before) << white << " ("
474  << 100. * std::get<2>(stats_before) / m_points.size() << "%)\n";
475 #endif
476 
477 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
478  std::cerr << yellow
479  << "\nAttempt to fix inconsistencies using perturbations - step #"
480  << info.num_steps + 1 << "... " << white;
481 #endif
482 
483  std::size_t num_inconsistent_stars = 0;
484  std::vector<std::size_t> updated_points;
485 
486 #ifdef GUDHI_TC_PROFILING
487  Gudhi::Clock t_fix_step;
488 #endif
489 
490  // Parallel
491 #if defined(GUDHI_USE_TBB)
492  if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
493  tbb::combinable<std::size_t> num_inconsistencies;
494  tbb::combinable<std::vector<std::size_t> > tls_updated_points;
495  tbb::parallel_for(
496  tbb::blocked_range<size_t>(0, m_triangulations.size()),
497  Try_to_solve_inconsistencies_in_a_local_triangulation(*this, max_perturb,
498  num_inconsistencies,
499  tls_updated_points));
500  num_inconsistent_stars =
501  num_inconsistencies.combine(std::plus<std::size_t>());
502  updated_points = tls_updated_points.combine(
503  [](std::vector<std::size_t> const& x,
504  std::vector<std::size_t> const& y) {
505  std::vector<std::size_t> res;
506  res.reserve(x.size() + y.size());
507  res.insert(res.end(), x.begin(), x.end());
508  res.insert(res.end(), y.begin(), y.end());
509  return res;
510  });
511  } else {
512 #endif // GUDHI_USE_TBB
513  // Sequential
514  for (std::size_t i = 0; i < m_triangulations.size(); ++i) {
515  num_inconsistent_stars +=
516  try_to_solve_inconsistencies_in_a_local_triangulation(i, max_perturb,
517  std::back_inserter(updated_points));
518  }
519 #if defined(GUDHI_USE_TBB)
520  }
521 #endif // GUDHI_USE_TBB
522 
523 #ifdef GUDHI_TC_PROFILING
524  t_fix_step.end();
525 #endif
526 
527 #if defined(GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES) || defined(DEBUG_TRACES)
528  std::cerr
529  << "\nEncountered during fix:\n"
530  << " * Num stars containing inconsistent simplices: "
531  << red << num_inconsistent_stars << white
532  << " (" << 100. * num_inconsistent_stars / m_points.size() << "%)\n";
533 #endif
534 
535 #ifdef GUDHI_TC_PROFILING
536  std::cerr << yellow << "done in " << t_fix_step.num_seconds()
537  << " seconds.\n" << white;
538 #elif defined(DEBUG_TRACES)
539  std::cerr << yellow << "done.\n" << white;
540 #endif
541 
542  if (num_inconsistent_stars > 0)
543  refresh_tangential_complex(updated_points);
544 
545 #ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
546  // Confirm that all stars were actually refreshed
547  std::size_t num_inc_1 =
548  std::get<1>(number_of_inconsistent_simplices(false));
549  refresh_tangential_complex();
550  std::size_t num_inc_2 =
551  std::get<1>(number_of_inconsistent_simplices(false));
552  if (num_inc_1 != num_inc_2)
553  std::cerr << red << "REFRESHMENT CHECK: FAILED. ("
554  << num_inc_1 << " vs " << num_inc_2 << ")\n" << white;
555  else
556  std::cerr << green << "REFRESHMENT CHECK: PASSED.\n" << white;
557 #endif
558 
559 #ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
560  std::tuple<std::size_t, std::size_t, std::size_t> stats_after =
561  number_of_inconsistent_simplices(false);
562 
563  std::cerr
564  << "\nAfter fix:\n"
565  << " * Total number of simplices in stars (incl. duplicates): "
566  << std::get<0>(stats_after) << "\n"
567  << " * Num inconsistent simplices in stars (incl. duplicates): "
568  << red << std::get<1>(stats_after) << white << " ("
569  << 100. * std::get<1>(stats_after) / std::get<0>(stats_after) << "%)\n"
570  << " * Number of stars containing inconsistent simplices: "
571  << red << std::get<2>(stats_after) << white << " ("
572  << 100. * std::get<2>(stats_after) / m_points.size() << "%)\n";
573 
574  stats_before = stats_after;
575 #endif
576 
577  if (info.num_steps == 0)
578  info.initial_num_inconsistent_stars = num_inconsistent_stars;
579 
580  if (num_inconsistent_stars < info.best_num_inconsistent_stars)
581  info.best_num_inconsistent_stars = num_inconsistent_stars;
582 
583  info.final_num_inconsistent_stars = num_inconsistent_stars;
584 
585  done = (num_inconsistent_stars == 0);
586  if (!done) {
587  ++info.num_steps;
588  if (time_limit > 0. && t.num_seconds() > time_limit) {
589 #ifdef DEBUG_TRACES
590  std::cerr << red << "Time limit reached.\n" << white;
591 #endif
592  info.success = false;
593  return info;
594  }
595  }
596  }
597 
598 #ifdef DEBUG_TRACES
599  std::cerr << green << "Fixed!\n" << white;
600 #endif
601  info.success = true;
602  return info;
603  }
604 
608  std::size_t num_simplices = 0;
610  std::size_t num_inconsistent_simplices = 0;
612  std::size_t num_inconsistent_stars = 0;
613  };
614 
617 
620 #ifdef DEBUG_TRACES
621  bool verbose = true
622 #else
623  bool verbose = false
624 #endif
625  ) const {
626  Num_inconsistencies stats;
627 
628  // For each triangulation
629  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
630  bool is_star_inconsistent = false;
631 
632  // For each cell
633  Star::const_iterator it_inc_simplex = m_stars[idx].begin();
634  Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
635  for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
636  // Don't check infinite cells
637  if (is_infinite(*it_inc_simplex))
638  continue;
639 
640  Simplex c = *it_inc_simplex;
641  c.insert(idx); // Add the missing index
642 
643  if (!is_simplex_consistent(c)) {
645  is_star_inconsistent = true;
646  }
647 
648  ++stats.num_simplices;
649  }
650  stats.num_inconsistent_stars += is_star_inconsistent;
651  }
652 
653  if (verbose) {
654  std::cerr
655  << "\n==========================================================\n"
656  << "Inconsistencies:\n"
657  << " * Total number of simplices in stars (incl. duplicates): "
658  << stats.num_simplices << "\n"
659  << " * Number of inconsistent simplices in stars (incl. duplicates): "
660  << stats.num_inconsistent_simplices << " ("
661  << 100. * stats.num_inconsistent_simplices / stats.num_simplices << "%)\n"
662  << " * Number of stars containing inconsistent simplices: "
663  << stats.num_inconsistent_stars << " ("
664  << 100. * stats.num_inconsistent_stars / m_points.size() << "%)\n"
665  << "==========================================================\n";
666  }
667 
668  return stats;
669  }
670 
681  template <typename Simplex_tree_>
682  int create_complex(Simplex_tree_ &tree
683  , bool export_inconsistent_simplices = true
685  , bool export_infinite_simplices = false
686  , Simplex_set *p_inconsistent_simplices = NULL
688  ) const {
689 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
690  std::cerr << yellow
691  << "\nExporting the TC as a Simplex_tree... " << white;
692 #endif
693 #ifdef GUDHI_TC_PROFILING
694  Gudhi::Clock t;
695 #endif
696 
697  int max_dim = -1;
698 
699  // For each triangulation
700  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
701  // For each cell of the star
702  Star::const_iterator it_inc_simplex = m_stars[idx].begin();
703  Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
704  for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
705  Simplex c = *it_inc_simplex;
706 
707  // Don't export infinite cells
708  if (!export_infinite_simplices && is_infinite(c))
709  continue;
710 
711  if (!export_inconsistent_simplices && !is_simplex_consistent(c))
712  continue;
713 
714  if (static_cast<int> (c.size()) > max_dim)
715  max_dim = static_cast<int> (c.size());
716  // Add the missing center vertex
717  c.insert(idx);
718 
719  // Try to insert the simplex
720  bool inserted = tree.insert_simplex_and_subfaces(c).second;
721 
722  // Inconsistent?
723  if (p_inconsistent_simplices && inserted && !is_simplex_consistent(c)) {
724  p_inconsistent_simplices->insert(c);
725  }
726  }
727  }
728 
729 #ifdef GUDHI_TC_PROFILING
730  t.end();
731  std::cerr << yellow << "done in " << t.num_seconds()
732  << " seconds.\n" << white;
733 #elif defined(DEBUG_TRACES)
734  std::cerr << yellow << "done.\n" << white;
735 #endif
736 
737  return max_dim;
738  }
739 
740  // First clears the complex then exports the TC into it
741  // Returns the max dimension of the simplices
742  // check_lower_and_higher_dim_simplices : 0 (false), 1 (true), 2 (auto)
743  // If the check is enabled, the function:
744  // - won't insert the simplex if it is already in a higher dim simplex
745  // - will erase any lower-dim simplices that are faces of the new simplex
746  // "auto" (= 2) will enable the check as a soon as it encounters a
747  // simplex whose dimension is different from the previous ones.
748  // N.B.: The check is quite expensive.
749 
750  int create_complex(Simplicial_complex &complex,
751  bool export_inconsistent_simplices = true,
752  bool export_infinite_simplices = false,
753  int check_lower_and_higher_dim_simplices = 2,
754  Simplex_set *p_inconsistent_simplices = NULL) const {
755 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
756  std::cerr << yellow
757  << "\nExporting the TC as a Simplicial_complex... " << white;
758 #endif
759 #ifdef GUDHI_TC_PROFILING
760  Gudhi::Clock t;
761 #endif
762 
763  int max_dim = -1;
764  complex.clear();
765 
766  // For each triangulation
767  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
768  // For each cell of the star
769  Star::const_iterator it_inc_simplex = m_stars[idx].begin();
770  Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
771  for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
772  Simplex c = *it_inc_simplex;
773 
774  // Don't export infinite cells
775  if (!export_infinite_simplices && is_infinite(c))
776  continue;
777 
778  if (!export_inconsistent_simplices && !is_simplex_consistent(c))
779  continue;
780 
781  // Unusual simplex dim?
782  if (check_lower_and_higher_dim_simplices == 2
783  && max_dim != -1
784  && static_cast<int> (c.size()) != max_dim) {
785  // Let's activate the check
786  std::cerr << red <<
787  "Info: check_lower_and_higher_dim_simplices ACTIVATED. "
788  "Export might be take some time...\n" << white;
789  check_lower_and_higher_dim_simplices = 1;
790  }
791 
792  if (static_cast<int> (c.size()) > max_dim)
793  max_dim = static_cast<int> (c.size());
794  // Add the missing center vertex
795  c.insert(idx);
796 
797  // Try to insert the simplex
798  bool added =
799  complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1);
800 
801  // Inconsistent?
802  if (p_inconsistent_simplices && added && !is_simplex_consistent(c)) {
803  p_inconsistent_simplices->insert(c);
804  }
805  }
806  }
807 
808 #ifdef GUDHI_TC_PROFILING
809  t.end();
810  std::cerr << yellow << "done in " << t.num_seconds()
811  << " seconds.\n" << white;
812 #elif defined(DEBUG_TRACES)
813  std::cerr << yellow << "done.\n" << white;
814 #endif
815 
816  return max_dim;
817  }
818 
819  template<typename ProjectionFunctor = CGAL::Identity<Point> >
820  std::ostream &export_to_off(
821  const Simplicial_complex &complex, std::ostream & os,
822  Simplex_set const *p_simpl_to_color_in_red = NULL,
823  Simplex_set const *p_simpl_to_color_in_green = NULL,
824  Simplex_set const *p_simpl_to_color_in_blue = NULL,
825  ProjectionFunctor const& point_projection = ProjectionFunctor())
826  const {
827  return export_to_off(
828  os, false, p_simpl_to_color_in_red, p_simpl_to_color_in_green,
829  p_simpl_to_color_in_blue, &complex, point_projection);
830  }
831 
832  template<typename ProjectionFunctor = CGAL::Identity<Point> >
833  std::ostream &export_to_off(
834  std::ostream & os, bool color_inconsistencies = false,
835  Simplex_set const *p_simpl_to_color_in_red = NULL,
836  Simplex_set const *p_simpl_to_color_in_green = NULL,
837  Simplex_set const *p_simpl_to_color_in_blue = NULL,
838  const Simplicial_complex *p_complex = NULL,
839  ProjectionFunctor const& point_projection = ProjectionFunctor()) const {
840  if (m_points.empty())
841  return os;
842 
843  if (m_ambient_dim < 2) {
844  std::cerr << "Error: export_to_off => ambient dimension should be >= 2.\n";
845  os << "Error: export_to_off => ambient dimension should be >= 2.\n";
846  return os;
847  }
848  if (m_ambient_dim > 3) {
849  std::cerr << "Warning: export_to_off => ambient dimension should be "
850  "<= 3. Only the first 3 coordinates will be exported.\n";
851  }
852 
853  if (m_intrinsic_dim < 1 || m_intrinsic_dim > 3) {
854  std::cerr << "Error: export_to_off => intrinsic dimension should be "
855  "between 1 and 3.\n";
856  os << "Error: export_to_off => intrinsic dimension should be "
857  "between 1 and 3.\n";
858  return os;
859  }
860 
861  std::stringstream output;
862  std::size_t num_simplices, num_vertices;
863  export_vertices_to_off(output, num_vertices, false, point_projection);
864  if (p_complex) {
865  export_simplices_to_off(
866  *p_complex, output, num_simplices, p_simpl_to_color_in_red,
867  p_simpl_to_color_in_green, p_simpl_to_color_in_blue);
868  } else {
869  export_simplices_to_off(
870  output, num_simplices, color_inconsistencies, p_simpl_to_color_in_red,
871  p_simpl_to_color_in_green, p_simpl_to_color_in_blue);
872  }
873 
874 #ifdef GUDHI_TC_EXPORT_NORMALS
875  os << "N";
876 #endif
877 
878  os << "OFF \n"
879  << num_vertices << " "
880  << num_simplices << " "
881  << "0 \n"
882  << output.str();
883 
884  return os;
885  }
886 
887  private:
888  void refresh_tangential_complex() {
889 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
890  std::cerr << yellow << "\nRefreshing TC... " << white;
891 #endif
892 
893 #ifdef GUDHI_TC_PROFILING
894  Gudhi::Clock t;
895 #endif
896 #ifdef GUDHI_USE_TBB
897  // Parallel
898  if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
899  tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()),
900  Compute_tangent_triangulation(*this));
901  } else {
902 #endif // GUDHI_USE_TBB
903  // Sequential
904  for (std::size_t i = 0; i < m_points.size(); ++i)
905  compute_tangent_triangulation(i);
906 #ifdef GUDHI_USE_TBB
907  }
908 #endif // GUDHI_USE_TBB
909 
910 #ifdef GUDHI_TC_PROFILING
911  t.end();
912  std::cerr << yellow << "done in " << t.num_seconds()
913  << " seconds.\n" << white;
914 #elif defined(DEBUG_TRACES)
915  std::cerr << yellow << "done.\n" << white;
916 #endif
917  }
918 
919  // If the list of perturbed points is provided, it is much faster
920  template <typename Point_indices_range>
921  void refresh_tangential_complex(
922  Point_indices_range const& perturbed_points_indices) {
923 #if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
924  std::cerr << yellow << "\nRefreshing TC... " << white;
925 #endif
926 
927 #ifdef GUDHI_TC_PROFILING
928  Gudhi::Clock t;
929 #endif
930 
931  // ANN tree containing only the perturbed points
932  Points_ds updated_pts_ds(m_points, perturbed_points_indices);
933 
934 #ifdef GUDHI_USE_TBB
935  // Parallel
936  if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
937  tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()),
938  Refresh_tangent_triangulation(*this, updated_pts_ds));
939  } else {
940 #endif // GUDHI_USE_TBB
941  // Sequential
942  for (std::size_t i = 0; i < m_points.size(); ++i)
943  refresh_tangent_triangulation(i, updated_pts_ds);
944 #ifdef GUDHI_USE_TBB
945  }
946 #endif // GUDHI_USE_TBB
947 
948 #ifdef GUDHI_TC_PROFILING
949  t.end();
950  std::cerr << yellow << "done in " << t.num_seconds()
951  << " seconds.\n" << white;
952 #elif defined(DEBUG_TRACES)
953  std::cerr << yellow << "done.\n" << white;
954 #endif
955  }
956 
957  void export_inconsistent_stars_to_OFF_files(std::string const& filename_base) const {
958  // For each triangulation
959  for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
960  // We build a SC along the way in case it's inconsistent
961  Simplicial_complex sc;
962  // For each cell
963  bool is_inconsistent = false;
964  Star::const_iterator it_inc_simplex = m_stars[idx].begin();
965  Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
966  for (; it_inc_simplex != it_inc_simplex_end;
967  ++it_inc_simplex) {
968  // Skip infinite cells
969  if (is_infinite(*it_inc_simplex))
970  continue;
971 
972  Simplex c = *it_inc_simplex;
973  c.insert(idx); // Add the missing index
974 
975  sc.add_simplex(c);
976 
977  // If we do not already know this star is inconsistent, test it
978  if (!is_inconsistent && !is_simplex_consistent(c))
979  is_inconsistent = true;
980  }
981 
982  if (is_inconsistent) {
983  // Export star to OFF file
984  std::stringstream output_filename;
985  output_filename << filename_base << "_" << idx << ".off";
986  std::ofstream off_stream(output_filename.str().c_str());
987  export_to_off(sc, off_stream);
988  }
989  }
990  }
991 
992  class Compare_distance_to_ref_point {
993  public:
994  Compare_distance_to_ref_point(Point const& ref, K const& k)
995  : m_ref(ref), m_k(k) { }
996 
997  bool operator()(Point const& p1, Point const& p2) {
998  typename K::Squared_distance_d sqdist =
999  m_k.squared_distance_d_object();
1000  return sqdist(p1, m_ref) < sqdist(p2, m_ref);
1001  }
1002 
1003  private:
1004  Point const& m_ref;
1005  K const& m_k;
1006  };
1007 
1008 #ifdef GUDHI_USE_TBB
1009  // Functor for compute_tangential_complex function
1010  class Compute_tangent_triangulation {
1011  Tangential_complex & m_tc;
1012 
1013  public:
1014  // Constructor
1015  Compute_tangent_triangulation(Tangential_complex &tc)
1016  : m_tc(tc) { }
1017 
1018  // Constructor
1019  Compute_tangent_triangulation(const Compute_tangent_triangulation &ctt)
1020  : m_tc(ctt.m_tc) { }
1021 
1022  // operator()
1023  void operator()(const tbb::blocked_range<size_t>& r) const {
1024  for (size_t i = r.begin(); i != r.end(); ++i)
1025  m_tc.compute_tangent_triangulation(i);
1026  }
1027  };
1028 
1029  // Functor for refresh_tangential_complex function
1030  class Refresh_tangent_triangulation {
1031  Tangential_complex & m_tc;
1032  Points_ds const& m_updated_pts_ds;
1033 
1034  public:
1035  // Constructor
1036  Refresh_tangent_triangulation(Tangential_complex &tc, Points_ds const& updated_pts_ds)
1037  : m_tc(tc), m_updated_pts_ds(updated_pts_ds) { }
1038 
1039  // Constructor
1040  Refresh_tangent_triangulation(const Refresh_tangent_triangulation &ctt)
1041  : m_tc(ctt.m_tc), m_updated_pts_ds(ctt.m_updated_pts_ds) { }
1042 
1043  // operator()
1044  void operator()(const tbb::blocked_range<size_t>& r) const {
1045  for (size_t i = r.begin(); i != r.end(); ++i)
1046  m_tc.refresh_tangent_triangulation(i, m_updated_pts_ds);
1047  }
1048  };
1049 #endif // GUDHI_USE_TBB
1050 
1051  bool is_infinite(Simplex const& s) const {
1052  return *s.rbegin() == (std::numeric_limits<std::size_t>::max)();
1053  }
1054 
1055  // Output: "triangulation" is a Regular Triangulation containing at least the
1056  // star of "center_pt"
1057  // Returns the handle of the center vertex
1058  Tr_vertex_handle compute_star(std::size_t i, const Point &center_pt, const Tangent_space_basis &tsb,
1059  Triangulation &triangulation, bool verbose = false) {
1060  int tangent_space_dim = tsb.dimension();
1061  const Tr_traits &local_tr_traits = triangulation.geom_traits();
1062 
1063  // Kernel functor & objects
1064  typename K::Squared_distance_d k_sqdist = m_k.squared_distance_d_object();
1065 
1066  // Triangulation's traits functor & objects
1067  typename Tr_traits::Compute_weight_d point_weight = local_tr_traits.compute_weight_d_object();
1068  typename Tr_traits::Power_center_d power_center = local_tr_traits.power_center_d_object();
1069 
1070  //***************************************************
1071  // Build a minimal triangulation in the tangent space
1072  // (we only need the star of p)
1073  //***************************************************
1074 
1075  // Insert p
1076  Tr_point proj_wp;
1077  if (i == tsb.origin()) {
1078  // Insert {(0, 0, 0...), m_weights[i]}
1079  proj_wp = local_tr_traits.construct_weighted_point_d_object()(local_tr_traits.construct_point_d_object()(tangent_space_dim, CGAL::ORIGIN),
1080  m_weights[i]);
1081  } else {
1082  const Weighted_point& wp = compute_perturbed_weighted_point(i);
1083  proj_wp = project_point_and_compute_weight(wp, tsb, local_tr_traits);
1084  }
1085 
1086  Tr_vertex_handle center_vertex = triangulation.insert(proj_wp);
1087  center_vertex->data() = i;
1088  if (verbose)
1089  std::cerr << "* Inserted point #" << i << "\n";
1090 
1091 #ifdef GUDHI_TC_VERY_VERBOSE
1092  std::size_t num_attempts_to_insert_points = 1;
1093  std::size_t num_inserted_points = 1;
1094 #endif
1095  // const int NUM_NEIGHBORS = 150;
1096  // KNS_range ins_range = m_points_ds.k_nearest_neighbors(center_pt, NUM_NEIGHBORS);
1097  INS_range ins_range = m_points_ds.incremental_nearest_neighbors(center_pt);
1098 
1099  // While building the local triangulation, we keep the radius
1100  // of the sphere "star sphere" centered at "center_vertex"
1101  // and which contains all the
1102  // circumspheres of the star of "center_vertex"
1103  boost::optional<FT> squared_star_sphere_radius_plus_margin = boost::make_optional(false, FT());
1104  // This is the strange way boost is recommending to get rid of "may be used uninitialized in this function".
1105  // Former code was :
1106  // boost::optional<FT> squared_star_sphere_radius_plus_margin;
1107 
1108  // Insert points until we find a point which is outside "star sphere"
1109  for (auto nn_it = ins_range.begin();
1110  nn_it != ins_range.end();
1111  ++nn_it) {
1112  std::size_t neighbor_point_idx = nn_it->first;
1113 
1114  // ith point = p, which is already inserted
1115  if (neighbor_point_idx != i) {
1116  // No need to lock the Mutex_for_perturb here since this will not be
1117  // called while other threads are perturbing the positions
1118  Point neighbor_pt;
1119  FT neighbor_weight;
1120  compute_perturbed_weighted_point(neighbor_point_idx, neighbor_pt, neighbor_weight);
1121 
1122  if (squared_star_sphere_radius_plus_margin &&
1123  k_sqdist(center_pt, neighbor_pt) > *squared_star_sphere_radius_plus_margin)
1124  break;
1125 
1126  Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb,
1127  local_tr_traits);
1128 
1129 #ifdef GUDHI_TC_VERY_VERBOSE
1130  ++num_attempts_to_insert_points;
1131 #endif
1132 
1133 
1134  Tr_vertex_handle vh = triangulation.insert_if_in_star(proj_pt, center_vertex);
1135  // Tr_vertex_handle vh = triangulation.insert(proj_pt);
1136  if (vh != Tr_vertex_handle() && vh->data() == (std::numeric_limits<std::size_t>::max)()) {
1137 #ifdef GUDHI_TC_VERY_VERBOSE
1138  ++num_inserted_points;
1139 #endif
1140  if (verbose)
1141  std::cerr << "* Inserted point #" << neighbor_point_idx << "\n";
1142 
1143  vh->data() = neighbor_point_idx;
1144 
1145  // Let's recompute squared_star_sphere_radius_plus_margin
1146  if (triangulation.current_dimension() >= tangent_space_dim) {
1147  squared_star_sphere_radius_plus_margin = boost::none;
1148  // Get the incident cells and look for the biggest circumsphere
1149  std::vector<Tr_full_cell_handle> incident_cells;
1150  triangulation.incident_full_cells(
1151  center_vertex,
1152  std::back_inserter(incident_cells));
1153  for (typename std::vector<Tr_full_cell_handle>::iterator cit =
1154  incident_cells.begin(); cit != incident_cells.end(); ++cit) {
1155  Tr_full_cell_handle cell = *cit;
1156  if (triangulation.is_infinite(cell)) {
1157  squared_star_sphere_radius_plus_margin = boost::none;
1158  break;
1159  } else {
1160  // Note that this uses the perturbed point since it uses
1161  // the points of the local triangulation
1162  Tr_point c = power_center(boost::make_transform_iterator(cell->vertices_begin(),
1163  vertex_handle_to_point<Tr_point,
1164  Tr_vertex_handle>),
1165  boost::make_transform_iterator(cell->vertices_end(),
1166  vertex_handle_to_point<Tr_point,
1167  Tr_vertex_handle>));
1168 
1169  FT sq_power_sphere_diam = 4 * point_weight(c);
1170 
1171  if (!squared_star_sphere_radius_plus_margin ||
1172  sq_power_sphere_diam > *squared_star_sphere_radius_plus_margin) {
1173  squared_star_sphere_radius_plus_margin = sq_power_sphere_diam;
1174  }
1175  }
1176  }
1177 
1178  // Let's add the margin, now
1179  // The value depends on whether we perturb weight or position
1180  if (squared_star_sphere_radius_plus_margin) {
1181  // "2*m_last_max_perturb" because both points can be perturbed
1182  squared_star_sphere_radius_plus_margin = CGAL::square(std::sqrt(*squared_star_sphere_radius_plus_margin)
1183  + 2 * m_last_max_perturb);
1184 
1185  // Save it in `m_squared_star_spheres_radii_incl_margin`
1186  m_squared_star_spheres_radii_incl_margin[i] =
1187  *squared_star_sphere_radius_plus_margin;
1188  } else {
1189  m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
1190  }
1191  }
1192  }
1193  }
1194  }
1195 
1196  return center_vertex;
1197  }
1198 
1199  void refresh_tangent_triangulation(std::size_t i, Points_ds const& updated_pts_ds, bool verbose = false) {
1200  if (verbose)
1201  std::cerr << "** Refreshing tangent tri #" << i << " **\n";
1202 
1203  if (m_squared_star_spheres_radii_incl_margin[i] == FT(-1))
1204  return compute_tangent_triangulation(i, verbose);
1205 
1206  Point center_point = compute_perturbed_point(i);
1207  // Among updated point, what is the closer from our center point?
1208  std::size_t closest_pt_index =
1209  updated_pts_ds.k_nearest_neighbors(center_point, 1, false).begin()->first;
1210 
1211  typename K::Construct_weighted_point_d k_constr_wp =
1212  m_k.construct_weighted_point_d_object();
1213  typename K::Power_distance_d k_power_dist = m_k.power_distance_d_object();
1214 
1215  // Construct a weighted point equivalent to the star sphere
1216  Weighted_point star_sphere = k_constr_wp(compute_perturbed_point(i),
1217  m_squared_star_spheres_radii_incl_margin[i]);
1218  Weighted_point closest_updated_point =
1219  compute_perturbed_weighted_point(closest_pt_index);
1220 
1221  // Is the "closest point" inside our star sphere?
1222  if (k_power_dist(star_sphere, closest_updated_point) <= FT(0))
1223  compute_tangent_triangulation(i, verbose);
1224  }
1225 
1226  void compute_tangent_triangulation(std::size_t i, bool verbose = false) {
1227  if (verbose)
1228  std::cerr << "** Computing tangent tri #" << i << " **\n";
1229  // std::cerr << "***********************************************\n";
1230 
1231  // No need to lock the mutex here since this will not be called while
1232  // other threads are perturbing the positions
1233  const Point center_pt = compute_perturbed_point(i);
1234  Tangent_space_basis &tsb = m_tangent_spaces[i];
1235 
1236  // Estimate the tangent space
1237  if (!m_are_tangent_spaces_computed[i]) {
1238 #ifdef GUDHI_TC_EXPORT_NORMALS
1239  tsb = compute_tangent_space(center_pt, i, true /*normalize*/, &m_orth_spaces[i]);
1240 #else
1241  tsb = compute_tangent_space(center_pt, i);
1242 #endif
1243  }
1244 
1245 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1246  Gudhi::Clock t;
1247 #endif
1248  int tangent_space_dim = tangent_basis_dim(i);
1249  Triangulation &local_tr =
1250  m_triangulations[i].construct_triangulation(tangent_space_dim);
1251 
1252  m_triangulations[i].center_vertex() =
1253  compute_star(i, center_pt, tsb, local_tr, verbose);
1254 
1255 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1256  t.end();
1257  std::cerr << " - triangulation construction: " << t.num_seconds() << " s.\n";
1258  t.reset();
1259 #endif
1260 
1261 #ifdef GUDHI_TC_VERY_VERBOSE
1262  std::cerr << "Inserted " << num_inserted_points << " points / "
1263  << num_attempts_to_insert_points << " attemps to compute the star\n";
1264 #endif
1265 
1266  update_star(i);
1267 
1268 #if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
1269  t.end();
1270  std::cerr << " - update_star: " << t.num_seconds() << " s.\n";
1271 #endif
1272  }
1273 
1274  // Updates m_stars[i] directly from m_triangulations[i]
1275 
1276  void update_star(std::size_t i) {
1277  Star &star = m_stars[i];
1278  star.clear();
1279  Triangulation &local_tr = m_triangulations[i].tr();
1280  Tr_vertex_handle center_vertex = m_triangulations[i].center_vertex();
1281  int cur_dim_plus_1 = local_tr.current_dimension() + 1;
1282 
1283  std::vector<Tr_full_cell_handle> incident_cells;
1284  local_tr.incident_full_cells(
1285  center_vertex, std::back_inserter(incident_cells));
1286 
1287  typename std::vector<Tr_full_cell_handle>::const_iterator it_c = incident_cells.begin();
1288  typename std::vector<Tr_full_cell_handle>::const_iterator it_c_end = incident_cells.end();
1289  // For each cell
1290  for (; it_c != it_c_end; ++it_c) {
1291  // Will contain all indices except center_vertex
1292  Incident_simplex incident_simplex;
1293  for (int j = 0; j < cur_dim_plus_1; ++j) {
1294  std::size_t index = (*it_c)->vertex(j)->data();
1295  if (index != i)
1296  incident_simplex.insert(index);
1297  }
1298  GUDHI_CHECK(incident_simplex.size() == cur_dim_plus_1 - 1,
1299  std::logic_error("update_star: wrong size of incident simplex"));
1300  star.push_back(incident_simplex);
1301  }
1302  }
1303 
1304  // Estimates tangent subspaces using PCA
1305 
1306  Tangent_space_basis compute_tangent_space(const Point &p
1307  , const std::size_t i
1308  , bool normalize_basis = true
1309  , Orthogonal_space_basis *p_orth_space_basis = NULL
1310  ) {
1311  unsigned int num_pts_for_pca = (std::min)(static_cast<unsigned int> (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
1312  static_cast<unsigned int> (m_points.size()));
1313 
1314  // Kernel functors
1315  typename K::Construct_vector_d constr_vec =
1316  m_k.construct_vector_d_object();
1317  typename K::Compute_coordinate_d coord =
1318  m_k.compute_coordinate_d_object();
1319 
1320 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
1321  KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false);
1322  const Points &points_for_pca = m_points_for_tse;
1323 #else
1324  KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false);
1325  const Points &points_for_pca = m_points;
1326 #endif
1327 
1328  // One row = one point
1329  Eigen::MatrixXd mat_points(num_pts_for_pca, m_ambient_dim);
1330  auto nn_it = kns_range.begin();
1331  for (unsigned int j = 0;
1332  j < num_pts_for_pca && nn_it != kns_range.end();
1333  ++j, ++nn_it) {
1334  for (int i = 0; i < m_ambient_dim; ++i) {
1335  mat_points(j, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i));
1336  }
1337  }
1338  Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
1339  Eigen::MatrixXd cov = centered.adjoint() * centered;
1340  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
1341 
1342  Tangent_space_basis tsb(i); // p = compute_perturbed_point(i) here
1343 
1344  // The eigenvectors are sorted in increasing order of their corresponding
1345  // eigenvalues
1346  for (int j = m_ambient_dim - 1;
1347  j >= m_ambient_dim - m_intrinsic_dim;
1348  --j) {
1349  if (normalize_basis) {
1350  Vector v = constr_vec(m_ambient_dim,
1351  eig.eigenvectors().col(j).data(),
1352  eig.eigenvectors().col(j).data() + m_ambient_dim);
1353  tsb.push_back(normalize_vector(v, m_k));
1354  } else {
1355  tsb.push_back(constr_vec(
1356  m_ambient_dim,
1357  eig.eigenvectors().col(j).data(),
1358  eig.eigenvectors().col(j).data() + m_ambient_dim));
1359  }
1360  }
1361 
1362  if (p_orth_space_basis) {
1363  p_orth_space_basis->set_origin(i);
1364  for (int j = m_ambient_dim - m_intrinsic_dim - 1;
1365  j >= 0;
1366  --j) {
1367  if (normalize_basis) {
1368  Vector v = constr_vec(m_ambient_dim,
1369  eig.eigenvectors().col(j).data(),
1370  eig.eigenvectors().col(j).data() + m_ambient_dim);
1371  p_orth_space_basis->push_back(normalize_vector(v, m_k));
1372  } else {
1373  p_orth_space_basis->push_back(constr_vec(
1374  m_ambient_dim,
1375  eig.eigenvectors().col(j).data(),
1376  eig.eigenvectors().col(j).data() + m_ambient_dim));
1377  }
1378  }
1379  }
1380 
1381  m_are_tangent_spaces_computed[i] = true;
1382 
1383  return tsb;
1384  }
1385 
1386  // Compute the space tangent to a simplex (p1, p2, ... pn)
1387  // TODO(CJ): Improve this?
1388  // Basically, it takes all the neighbor points to p1, p2... pn and runs PCA
1389  // on it. Note that most points are duplicated.
1390 
1391  Tangent_space_basis compute_tangent_space(const Simplex &s, bool normalize_basis = true) {
1392  unsigned int num_pts_for_pca = (std::min)(static_cast<unsigned int> (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
1393  static_cast<unsigned int> (m_points.size()));
1394 
1395  // Kernel functors
1396  typename K::Construct_vector_d constr_vec =
1397  m_k.construct_vector_d_object();
1398  typename K::Compute_coordinate_d coord =
1399  m_k.compute_coordinate_d_object();
1400  typename K::Squared_length_d sqlen =
1401  m_k.squared_length_d_object();
1402  typename K::Scaled_vector_d scaled_vec =
1403  m_k.scaled_vector_d_object();
1404  typename K::Scalar_product_d scalar_pdct =
1405  m_k.scalar_product_d_object();
1406  typename K::Difference_of_vectors_d diff_vec =
1407  m_k.difference_of_vectors_d_object();
1408 
1409  // One row = one point
1410  Eigen::MatrixXd mat_points(s.size() * num_pts_for_pca, m_ambient_dim);
1411  unsigned int current_row = 0;
1412 
1413  for (Simplex::const_iterator it_index = s.begin();
1414  it_index != s.end(); ++it_index) {
1415  const Point &p = m_points[*it_index];
1416 
1417 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
1418  KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false);
1419  const Points &points_for_pca = m_points_for_tse;
1420 #else
1421  KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false);
1422  const Points &points_for_pca = m_points;
1423 #endif
1424 
1425  auto nn_it = kns_range.begin();
1426  for (;
1427  current_row < num_pts_for_pca && nn_it != kns_range.end();
1428  ++current_row, ++nn_it) {
1429  for (int i = 0; i < m_ambient_dim; ++i) {
1430  mat_points(current_row, i) =
1431  CGAL::to_double(coord(points_for_pca[nn_it->first], i));
1432  }
1433  }
1434  }
1435  Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
1436  Eigen::MatrixXd cov = centered.adjoint() * centered;
1437  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
1438 
1439  Tangent_space_basis tsb;
1440 
1441  // The eigenvectors are sorted in increasing order of their corresponding
1442  // eigenvalues
1443  for (int j = m_ambient_dim - 1;
1444  j >= m_ambient_dim - m_intrinsic_dim;
1445  --j) {
1446  if (normalize_basis) {
1447  Vector v = constr_vec(m_ambient_dim,
1448  eig.eigenvectors().col(j).data(),
1449  eig.eigenvectors().col(j).data() + m_ambient_dim);
1450  tsb.push_back(normalize_vector(v, m_k));
1451  } else {
1452  tsb.push_back(constr_vec(
1453  m_ambient_dim,
1454  eig.eigenvectors().col(j).data(),
1455  eig.eigenvectors().col(j).data() + m_ambient_dim));
1456  }
1457  }
1458 
1459  return tsb;
1460  }
1461 
1462  // Returns the dimension of the ith local triangulation
1463 
1464  int tangent_basis_dim(std::size_t i) const {
1465  return m_tangent_spaces[i].dimension();
1466  }
1467 
1468  Point compute_perturbed_point(std::size_t pt_idx) const {
1469 #ifdef GUDHI_TC_PERTURB_POSITION
1470  return m_k.translated_point_d_object()(
1471  m_points[pt_idx], m_translations[pt_idx]);
1472 #else
1473  return m_points[pt_idx];
1474 #endif
1475  }
1476 
1477  void compute_perturbed_weighted_point(std::size_t pt_idx, Point &p, FT &w) const {
1478 #ifdef GUDHI_TC_PERTURB_POSITION
1479  p = m_k.translated_point_d_object()(
1480  m_points[pt_idx], m_translations[pt_idx]);
1481 #else
1482  p = m_points[pt_idx];
1483 #endif
1484  w = m_weights[pt_idx];
1485  }
1486 
1487  Weighted_point compute_perturbed_weighted_point(std::size_t pt_idx) const {
1488  typename K::Construct_weighted_point_d k_constr_wp =
1489  m_k.construct_weighted_point_d_object();
1490 
1491  Weighted_point wp = k_constr_wp(
1492 #ifdef GUDHI_TC_PERTURB_POSITION
1493  m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]),
1494 #else
1495  m_points[pt_idx],
1496 #endif
1497  m_weights[pt_idx]);
1498 
1499  return wp;
1500  }
1501 
1502  Point unproject_point(const Tr_point &p,
1503  const Tangent_space_basis &tsb,
1504  const Tr_traits &tr_traits) const {
1505  typename K::Translated_point_d k_transl =
1506  m_k.translated_point_d_object();
1507  typename K::Scaled_vector_d k_scaled_vec =
1508  m_k.scaled_vector_d_object();
1509  typename Tr_traits::Compute_coordinate_d coord =
1510  tr_traits.compute_coordinate_d_object();
1511 
1512  Point global_point = compute_perturbed_point(tsb.origin());
1513  for (int i = 0; i < m_intrinsic_dim; ++i)
1514  global_point = k_transl(global_point,
1515  k_scaled_vec(tsb[i], coord(p, i)));
1516 
1517  return global_point;
1518  }
1519 
1520  // Project the point in the tangent space
1521  // Resulting point coords are expressed in tsb's space
1522  Tr_bare_point project_point(const Point &p,
1523  const Tangent_space_basis &tsb,
1524  const Tr_traits &tr_traits) const {
1525  typename K::Scalar_product_d scalar_pdct =
1526  m_k.scalar_product_d_object();
1527  typename K::Difference_of_points_d diff_points =
1528  m_k.difference_of_points_d_object();
1529 
1530  Vector v = diff_points(p, compute_perturbed_point(tsb.origin()));
1531 
1532  std::vector<FT> coords;
1533  // Ambiant-space coords of the projected point
1534  coords.reserve(tsb.dimension());
1535  for (std::size_t i = 0; i < m_intrinsic_dim; ++i) {
1536  // Local coords are given by the scalar product with the vectors of tsb
1537  FT coord = scalar_pdct(v, tsb[i]);
1538  coords.push_back(coord);
1539  }
1540 
1541  return tr_traits.construct_point_d_object()(
1542  static_cast<int> (coords.size()), coords.begin(), coords.end());
1543  }
1544 
1545  // Project the point in the tangent space
1546  // The weight will be the squared distance between p and the projection of p
1547  // Resulting point coords are expressed in tsb's space
1548 
1549  Tr_point project_point_and_compute_weight(const Weighted_point &wp,
1550  const Tangent_space_basis &tsb,
1551  const Tr_traits &tr_traits) const {
1552  typename K::Point_drop_weight_d k_drop_w =
1553  m_k.point_drop_weight_d_object();
1554  typename K::Compute_weight_d k_point_weight =
1555  m_k.compute_weight_d_object();
1556  return project_point_and_compute_weight(
1557  k_drop_w(wp), k_point_weight(wp), tsb, tr_traits);
1558  }
1559 
1560  // Same as above, with slightly different parameters
1561  Tr_point project_point_and_compute_weight(const Point &p, const FT w,
1562  const Tangent_space_basis &tsb,
1563  const Tr_traits &tr_traits) const {
1564  const int point_dim = m_k.point_dimension_d_object()(p);
1565 
1566  typename K::Construct_point_d constr_pt =
1567  m_k.construct_point_d_object();
1568  typename K::Scalar_product_d scalar_pdct =
1569  m_k.scalar_product_d_object();
1570  typename K::Difference_of_points_d diff_points =
1571  m_k.difference_of_points_d_object();
1572  typename K::Compute_coordinate_d coord =
1573  m_k.compute_coordinate_d_object();
1574  typename K::Construct_cartesian_const_iterator_d ccci =
1575  m_k.construct_cartesian_const_iterator_d_object();
1576 
1577  Point origin = compute_perturbed_point(tsb.origin());
1578  Vector v = diff_points(p, origin);
1579 
1580  // Same dimension? Then the weight is 0
1581  bool same_dim = (point_dim == tsb.dimension());
1582 
1583  std::vector<FT> coords;
1584  // Ambiant-space coords of the projected point
1585  std::vector<FT> p_proj(ccci(origin), ccci(origin, 0));
1586  coords.reserve(tsb.dimension());
1587  for (int i = 0; i < tsb.dimension(); ++i) {
1588  // Local coords are given by the scalar product with the vectors of tsb
1589  FT c = scalar_pdct(v, tsb[i]);
1590  coords.push_back(c);
1591 
1592  // p_proj += c * tsb[i]
1593  if (!same_dim) {
1594  for (int j = 0; j < point_dim; ++j)
1595  p_proj[j] += c * coord(tsb[i], j);
1596  }
1597  }
1598 
1599  // Same dimension? Then the weight is 0
1600  FT sq_dist_to_proj_pt = 0;
1601  if (!same_dim) {
1602  Point projected_pt = constr_pt(point_dim, p_proj.begin(), p_proj.end());
1603  sq_dist_to_proj_pt = m_k.squared_distance_d_object()(p, projected_pt);
1604  }
1605 
1606  return tr_traits.construct_weighted_point_d_object()
1607  (tr_traits.construct_point_d_object()(static_cast<int> (coords.size()), coords.begin(), coords.end()),
1608  w - sq_dist_to_proj_pt);
1609  }
1610 
1611  // Project all the points in the tangent space
1612 
1613  template <typename Indexed_point_range>
1614  std::vector<Tr_point> project_points_and_compute_weights(
1615  const Indexed_point_range &point_indices,
1616  const Tangent_space_basis &tsb,
1617  const Tr_traits &tr_traits) const {
1618  std::vector<Tr_point> ret;
1619  for (typename Indexed_point_range::const_iterator
1620  it = point_indices.begin(), it_end = point_indices.end();
1621  it != it_end; ++it) {
1622  ret.push_back(project_point_and_compute_weight(
1623  compute_perturbed_weighted_point(*it), tsb, tr_traits));
1624  }
1625  return ret;
1626  }
1627 
1628  // A simplex here is a local tri's full cell handle
1629 
1630  bool is_simplex_consistent(Tr_full_cell_handle fch, int cur_dim) const {
1631  Simplex c;
1632  for (int i = 0; i < cur_dim + 1; ++i) {
1633  std::size_t data = fch->vertex(i)->data();
1634  c.insert(data);
1635  }
1636  return is_simplex_consistent(c);
1637  }
1638 
1639  // A simplex here is a list of point indices
1640  // TODO(CJ): improve it like the other "is_simplex_consistent" below
1641 
1642  bool is_simplex_consistent(Simplex const& simplex) const {
1643  // Check if the simplex is in the stars of all its vertices
1644  Simplex::const_iterator it_point_idx = simplex.begin();
1645  // For each point p of the simplex, we parse the incidents cells of p
1646  // and we check if "simplex" is among them
1647  for (; it_point_idx != simplex.end(); ++it_point_idx) {
1648  std::size_t point_idx = *it_point_idx;
1649  // Don't check infinite simplices
1650  if (point_idx == (std::numeric_limits<std::size_t>::max)())
1651  continue;
1652 
1653  Star const& star = m_stars[point_idx];
1654 
1655  // What we're looking for is "simplex" \ point_idx
1656  Incident_simplex is_to_find = simplex;
1657  is_to_find.erase(point_idx);
1658 
1659  // For each cell
1660  if (std::find(star.begin(), star.end(), is_to_find) == star.end())
1661  return false;
1662  }
1663 
1664  return true;
1665  }
1666 
1667  // A simplex here is a list of point indices
1668  // "s" contains all the points of the simplex except "center_point"
1669  // This function returns the points whose star doesn't contain the simplex
1670  // N.B.: the function assumes that the simplex is contained in
1671  // star(center_point)
1672 
1673  template <typename OutputIterator> // value_type = std::size_t
1674  bool is_simplex_consistent(
1675  std::size_t center_point,
1676  Incident_simplex const& s, // without "center_point"
1677  OutputIterator points_whose_star_does_not_contain_s,
1678  bool check_also_in_non_maximal_faces = false) const {
1679  Simplex full_simplex = s;
1680  full_simplex.insert(center_point);
1681 
1682  // Check if the simplex is in the stars of all its vertices
1683  Incident_simplex::const_iterator it_point_idx = s.begin();
1684  // For each point p of the simplex, we parse the incidents cells of p
1685  // and we check if "simplex" is among them
1686  for (; it_point_idx != s.end(); ++it_point_idx) {
1687  std::size_t point_idx = *it_point_idx;
1688  // Don't check infinite simplices
1689  if (point_idx == (std::numeric_limits<std::size_t>::max)())
1690  continue;
1691 
1692  Star const& star = m_stars[point_idx];
1693 
1694  // What we're looking for is full_simplex \ point_idx
1695  Incident_simplex is_to_find = full_simplex;
1696  is_to_find.erase(point_idx);
1697 
1698  if (check_also_in_non_maximal_faces) {
1699  // For each simplex "is" of the star, check if ic_to_simplex is
1700  // included in "is"
1701  bool found = false;
1702  for (Star::const_iterator is = star.begin(), is_end = star.end();
1703  !found && is != is_end; ++is) {
1704  if (std::includes(is->begin(), is->end(),
1705  is_to_find.begin(), is_to_find.end()))
1706  found = true;
1707  }
1708 
1709  if (!found)
1710  *points_whose_star_does_not_contain_s++ = point_idx;
1711  } else {
1712  // Does the star contain is_to_find?
1713  if (std::find(star.begin(), star.end(), is_to_find) == star.end())
1714  *points_whose_star_does_not_contain_s++ = point_idx;
1715  }
1716  }
1717 
1718  return true;
1719  }
1720 
1721  // A simplex here is a list of point indices
1722  // It looks for s in star(p).
1723  // "s" contains all the points of the simplex except p.
1724  bool is_simplex_in_star(std::size_t p,
1725  Incident_simplex const& s,
1726  bool check_also_in_non_maximal_faces = true) const {
1727  Star const& star = m_stars[p];
1728 
1729  if (check_also_in_non_maximal_faces) {
1730  // For each simplex "is" of the star, check if ic_to_simplex is
1731  // included in "is"
1732  bool found = false;
1733  for (Star::const_iterator is = star.begin(), is_end = star.end();
1734  !found && is != is_end; ++is) {
1735  if (std::includes(is->begin(), is->end(), s.begin(), s.end()))
1736  found = true;
1737  }
1738 
1739  return found;
1740  } else {
1741  return !(std::find(star.begin(), star.end(), s) == star.end());
1742  }
1743  }
1744 
1745 #ifdef GUDHI_USE_TBB
1746  // Functor for try_to_solve_inconsistencies_in_a_local_triangulation function
1747  class Try_to_solve_inconsistencies_in_a_local_triangulation {
1748  Tangential_complex & m_tc;
1749  double m_max_perturb;
1750  tbb::combinable<std::size_t> &m_num_inconsistencies;
1751  tbb::combinable<std::vector<std::size_t> > &m_updated_points;
1752 
1753  public:
1754  // Constructor
1755  Try_to_solve_inconsistencies_in_a_local_triangulation(Tangential_complex &tc,
1756  double max_perturb,
1757  tbb::combinable<std::size_t> &num_inconsistencies,
1758  tbb::combinable<std::vector<std::size_t> > &updated_points)
1759  : m_tc(tc),
1760  m_max_perturb(max_perturb),
1761  m_num_inconsistencies(num_inconsistencies),
1762  m_updated_points(updated_points) { }
1763 
1764  // Constructor
1765  Try_to_solve_inconsistencies_in_a_local_triangulation(const Try_to_solve_inconsistencies_in_a_local_triangulation&
1766  tsilt)
1767  : m_tc(tsilt.m_tc),
1768  m_max_perturb(tsilt.m_max_perturb),
1769  m_num_inconsistencies(tsilt.m_num_inconsistencies),
1770  m_updated_points(tsilt.m_updated_points) { }
1771 
1772  // operator()
1773  void operator()(const tbb::blocked_range<size_t>& r) const {
1774  for (size_t i = r.begin(); i != r.end(); ++i) {
1775  m_num_inconsistencies.local() +=
1776  m_tc.try_to_solve_inconsistencies_in_a_local_triangulation(i, m_max_perturb,
1777  std::back_inserter(m_updated_points.local()));
1778  }
1779  }
1780  };
1781 #endif // GUDHI_USE_TBB
1782 
1783  void perturb(std::size_t point_idx, double max_perturb) {
1784  const Tr_traits &local_tr_traits =
1785  m_triangulations[point_idx].tr().geom_traits();
1786  typename Tr_traits::Compute_coordinate_d coord =
1787  local_tr_traits.compute_coordinate_d_object();
1788  typename K::Translated_point_d k_transl =
1789  m_k.translated_point_d_object();
1790  typename K::Construct_vector_d k_constr_vec =
1791  m_k.construct_vector_d_object();
1792  typename K::Scaled_vector_d k_scaled_vec =
1793  m_k.scaled_vector_d_object();
1794 
1795  CGAL::Random_points_in_ball_d<Tr_bare_point>
1796  tr_point_in_ball_generator(m_intrinsic_dim,
1797  m_random_generator.get_double(0., max_perturb));
1798 
1799  Tr_point local_random_transl =
1800  local_tr_traits.construct_weighted_point_d_object()(*tr_point_in_ball_generator++, 0);
1801  Translation_for_perturb global_transl = k_constr_vec(m_ambient_dim);
1802  const Tangent_space_basis &tsb = m_tangent_spaces[point_idx];
1803  for (int i = 0; i < m_intrinsic_dim; ++i) {
1804  global_transl = k_transl(global_transl,
1805  k_scaled_vec(tsb[i], coord(local_random_transl, i)));
1806  }
1807  // Parallel
1808 #if defined(GUDHI_USE_TBB)
1809  m_p_perturb_mutexes[point_idx].lock();
1810  m_translations[point_idx] = global_transl;
1811  m_p_perturb_mutexes[point_idx].unlock();
1812  // Sequential
1813 #else
1814  m_translations[point_idx] = global_transl;
1815 #endif
1816  }
1817 
1818  // Return true if inconsistencies were found
1819  template <typename OutputIt>
1820  bool try_to_solve_inconsistencies_in_a_local_triangulation(std::size_t tr_index,
1821  double max_perturb,
1822  OutputIt perturbed_pts_indices = CGAL::Emptyset_iterator()) {
1823  bool is_inconsistent = false;
1824 
1825  Star const& star = m_stars[tr_index];
1826 
1827  // For each incident simplex
1828  Star::const_iterator it_inc_simplex = star.begin();
1829  Star::const_iterator it_inc_simplex_end = star.end();
1830  for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
1831  const Incident_simplex &incident_simplex = *it_inc_simplex;
1832 
1833  // Don't check infinite cells
1834  if (is_infinite(incident_simplex))
1835  continue;
1836 
1837  Simplex c = incident_simplex;
1838  c.insert(tr_index); // Add the missing index
1839 
1840  // Perturb the center point
1841  if (!is_simplex_consistent(c)) {
1842  is_inconsistent = true;
1843 
1844  std::size_t idx = tr_index;
1845 
1846  perturb(tr_index, max_perturb);
1847  *perturbed_pts_indices++ = idx;
1848 
1849  // We will try the other cells next time
1850  break;
1851  }
1852  }
1853 
1854  return is_inconsistent;
1855  }
1856 
1857 
1858  // 1st line: number of points
1859  // Then one point per line
1860  std::ostream &export_point_set(std::ostream & os,
1861  bool use_perturbed_points = false,
1862  const char *coord_separator = " ") const {
1863  if (use_perturbed_points) {
1864  std::vector<Point> perturbed_points;
1865  perturbed_points.reserve(m_points.size());
1866  for (std::size_t i = 0; i < m_points.size(); ++i)
1867  perturbed_points.push_back(compute_perturbed_point(i));
1868 
1869  return export_point_set(
1870  m_k, perturbed_points, os, coord_separator);
1871  } else {
1872  return export_point_set(
1873  m_k, m_points, os, coord_separator);
1874  }
1875  }
1876 
1877  template<typename ProjectionFunctor = CGAL::Identity<Point> >
1878  std::ostream &export_vertices_to_off(
1879  std::ostream & os, std::size_t &num_vertices,
1880  bool use_perturbed_points = false,
1881  ProjectionFunctor const& point_projection = ProjectionFunctor()) const {
1882  if (m_points.empty()) {
1883  num_vertices = 0;
1884  return os;
1885  }
1886 
1887  // If m_intrinsic_dim = 1, we output each point two times
1888  // to be able to export each segment as a flat triangle with 3 different
1889  // indices (otherwise, Meshlab detects degenerated simplices)
1890  const int N = (m_intrinsic_dim == 1 ? 2 : 1);
1891 
1892  // Kernel functors
1893  typename K::Compute_coordinate_d coord =
1894  m_k.compute_coordinate_d_object();
1895 
1896 #ifdef GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF
1897  int num_coords = m_ambient_dim;
1898 #else
1899  int num_coords = (std::min)(m_ambient_dim, 3);
1900 #endif
1901 
1902 #ifdef GUDHI_TC_EXPORT_NORMALS
1903  OS_container::const_iterator it_os = m_orth_spaces.begin();
1904 #endif
1905  typename Points::const_iterator it_p = m_points.begin();
1906  typename Points::const_iterator it_p_end = m_points.end();
1907  // For each point p
1908  for (std::size_t i = 0; it_p != it_p_end; ++it_p, ++i) {
1909  Point p = point_projection(
1910  use_perturbed_points ? compute_perturbed_point(i) : *it_p);
1911  for (int ii = 0; ii < N; ++ii) {
1912  int j = 0;
1913  for (; j < num_coords; ++j)
1914  os << CGAL::to_double(coord(p, j)) << " ";
1915  if (j == 2)
1916  os << "0";
1917 
1918 #ifdef GUDHI_TC_EXPORT_NORMALS
1919  for (j = 0; j < num_coords; ++j)
1920  os << " " << CGAL::to_double(coord(*it_os->begin(), j));
1921 #endif
1922  os << "\n";
1923  }
1924 #ifdef GUDHI_TC_EXPORT_NORMALS
1925  ++it_os;
1926 #endif
1927  }
1928 
1929  num_vertices = N * m_points.size();
1930  return os;
1931  }
1932 
1933  std::ostream &export_simplices_to_off(std::ostream & os, std::size_t &num_OFF_simplices,
1934  bool color_inconsistencies = false,
1935  Simplex_set const *p_simpl_to_color_in_red = NULL,
1936  Simplex_set const *p_simpl_to_color_in_green = NULL,
1937  Simplex_set const *p_simpl_to_color_in_blue = NULL)
1938  const {
1939  // If m_intrinsic_dim = 1, each point is output two times
1940  // (see export_vertices_to_off)
1941  num_OFF_simplices = 0;
1942  std::size_t num_maximal_simplices = 0;
1943  std::size_t num_inconsistent_maximal_simplices = 0;
1944  std::size_t num_inconsistent_stars = 0;
1945  typename Tr_container::const_iterator it_tr = m_triangulations.begin();
1946  typename Tr_container::const_iterator it_tr_end = m_triangulations.end();
1947  // For each triangulation
1948  for (std::size_t idx = 0; it_tr != it_tr_end; ++it_tr, ++idx) {
1949  bool is_star_inconsistent = false;
1950 
1951  Triangulation const& tr = it_tr->tr();
1952 
1953  if (tr.current_dimension() < m_intrinsic_dim)
1954  continue;
1955 
1956  // Color for this star
1957  std::stringstream color;
1958  // color << rand()%256 << " " << 100+rand()%156 << " " << 100+rand()%156;
1959  color << 128 << " " << 128 << " " << 128;
1960 
1961  // Gather the triangles here, with an int telling its color
1962  typedef std::vector<std::pair<Simplex, int> > Star_using_triangles;
1963  Star_using_triangles star_using_triangles;
1964 
1965  // For each cell of the star
1966  Star::const_iterator it_inc_simplex = m_stars[idx].begin();
1967  Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
1968  for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
1969  Simplex c = *it_inc_simplex;
1970  c.insert(idx);
1971  std::size_t num_vertices = c.size();
1972  ++num_maximal_simplices;
1973 
1974  int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
1975  if (color_inconsistencies && !is_simplex_consistent(c)) {
1976  ++num_inconsistent_maximal_simplices;
1977  color_simplex = 0;
1978  is_star_inconsistent = true;
1979  } else {
1980  if (p_simpl_to_color_in_red &&
1981  std::find(
1982  p_simpl_to_color_in_red->begin(),
1983  p_simpl_to_color_in_red->end(),
1984  c) != p_simpl_to_color_in_red->end()) {
1985  color_simplex = 1;
1986  } else if (p_simpl_to_color_in_green &&
1987  std::find(
1988  p_simpl_to_color_in_green->begin(),
1989  p_simpl_to_color_in_green->end(),
1990  c) != p_simpl_to_color_in_green->end()) {
1991  color_simplex = 2;
1992  } else if (p_simpl_to_color_in_blue &&
1993  std::find(
1994  p_simpl_to_color_in_blue->begin(),
1995  p_simpl_to_color_in_blue->end(),
1996  c) != p_simpl_to_color_in_blue->end()) {
1997  color_simplex = 3;
1998  }
1999  }
2000 
2001  // If m_intrinsic_dim = 1, each point is output two times,
2002  // so we need to multiply each index by 2
2003  // And if only 2 vertices, add a third one (each vertex is duplicated in
2004  // the file when m_intrinsic dim = 2)
2005  if (m_intrinsic_dim == 1) {
2006  Simplex tmp_c;
2007  Simplex::iterator it = c.begin();
2008  for (; it != c.end(); ++it)
2009  tmp_c.insert(*it * 2);
2010  if (num_vertices == 2)
2011  tmp_c.insert(*tmp_c.rbegin() + 1);
2012 
2013  c = tmp_c;
2014  }
2015 
2016  if (num_vertices <= 3) {
2017  star_using_triangles.push_back(std::make_pair(c, color_simplex));
2018  } else {
2019  // num_vertices >= 4: decompose the simplex in triangles
2020  std::vector<bool> booleans(num_vertices, false);
2021  std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
2022  do {
2023  Simplex triangle;
2024  Simplex::iterator it = c.begin();
2025  for (int i = 0; it != c.end(); ++i, ++it) {
2026  if (booleans[i])
2027  triangle.insert(*it);
2028  }
2029  star_using_triangles.push_back(
2030  std::make_pair(triangle, color_simplex));
2031  } while (std::next_permutation(booleans.begin(), booleans.end()));
2032  }
2033  }
2034 
2035  // For each cell
2036  Star_using_triangles::const_iterator it_simplex =
2037  star_using_triangles.begin();
2038  Star_using_triangles::const_iterator it_simplex_end =
2039  star_using_triangles.end();
2040  for (; it_simplex != it_simplex_end; ++it_simplex) {
2041  const Simplex &c = it_simplex->first;
2042 
2043  // Don't export infinite cells
2044  if (is_infinite(c))
2045  continue;
2046 
2047  int color_simplex = it_simplex->second;
2048 
2049  std::stringstream sstr_c;
2050 
2051  Simplex::const_iterator it_point_idx = c.begin();
2052  for (; it_point_idx != c.end(); ++it_point_idx) {
2053  sstr_c << *it_point_idx << " ";
2054  }
2055 
2056  os << 3 << " " << sstr_c.str();
2057  if (color_inconsistencies || p_simpl_to_color_in_red
2058  || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
2059  switch (color_simplex) {
2060  case 0: os << " 255 255 0";
2061  break;
2062  case 1: os << " 255 0 0";
2063  break;
2064  case 2: os << " 0 255 0";
2065  break;
2066  case 3: os << " 0 0 255";
2067  break;
2068  default: os << " " << color.str();
2069  break;
2070  }
2071  }
2072  ++num_OFF_simplices;
2073  os << "\n";
2074  }
2075  if (is_star_inconsistent)
2076  ++num_inconsistent_stars;
2077  }
2078 
2079 #ifdef DEBUG_TRACES
2080  std::cerr
2081  << "\n==========================================================\n"
2082  << "Export from list of stars to OFF:\n"
2083  << " * Number of vertices: " << m_points.size() << "\n"
2084  << " * Total number of maximal simplices: " << num_maximal_simplices
2085  << "\n";
2086  if (color_inconsistencies) {
2087  std::cerr
2088  << " * Number of inconsistent stars: "
2089  << num_inconsistent_stars << " ("
2090  << (m_points.size() > 0 ?
2091  100. * num_inconsistent_stars / m_points.size() : 0.) << "%)\n"
2092  << " * Number of inconsistent maximal simplices: "
2093  << num_inconsistent_maximal_simplices << " ("
2094  << (num_maximal_simplices > 0 ?
2095  100. * num_inconsistent_maximal_simplices / num_maximal_simplices
2096  : 0.) << "%)\n";
2097  }
2098  std::cerr << "==========================================================\n";
2099 #endif
2100 
2101  return os;
2102  }
2103 
2104  public:
2105  std::ostream &export_simplices_to_off(
2106  const Simplicial_complex &complex,
2107  std::ostream & os, std::size_t &num_OFF_simplices,
2108  Simplex_set const *p_simpl_to_color_in_red = NULL,
2109  Simplex_set const *p_simpl_to_color_in_green = NULL,
2110  Simplex_set const *p_simpl_to_color_in_blue = NULL)
2111  const {
2112  typedef Simplicial_complex::Simplex Simplex;
2113  typedef Simplicial_complex::Simplex_set Simplex_set;
2114 
2115  // If m_intrinsic_dim = 1, each point is output two times
2116  // (see export_vertices_to_off)
2117  num_OFF_simplices = 0;
2118  std::size_t num_maximal_simplices = 0;
2119 
2120  typename Simplex_set::const_iterator it_s =
2121  complex.simplex_range().begin();
2122  typename Simplex_set::const_iterator it_s_end =
2123  complex.simplex_range().end();
2124  // For each simplex
2125  for (; it_s != it_s_end; ++it_s) {
2126  Simplex c = *it_s;
2127  ++num_maximal_simplices;
2128 
2129  int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
2130  if (p_simpl_to_color_in_red &&
2131  std::find(
2132  p_simpl_to_color_in_red->begin(),
2133  p_simpl_to_color_in_red->end(),
2134  c) != p_simpl_to_color_in_red->end()) {
2135  color_simplex = 1;
2136  } else if (p_simpl_to_color_in_green &&
2137  std::find(p_simpl_to_color_in_green->begin(),
2138  p_simpl_to_color_in_green->end(),
2139  c) != p_simpl_to_color_in_green->end()) {
2140  color_simplex = 2;
2141  } else if (p_simpl_to_color_in_blue &&
2142  std::find(p_simpl_to_color_in_blue->begin(),
2143  p_simpl_to_color_in_blue->end(),
2144  c) != p_simpl_to_color_in_blue->end()) {
2145  color_simplex = 3;
2146  }
2147 
2148  // Gather the triangles here
2149  typedef std::vector<Simplex> Triangles;
2150  Triangles triangles;
2151 
2152  int num_vertices = static_cast<int>(c.size());
2153  // Do not export smaller dimension simplices
2154  if (num_vertices < m_intrinsic_dim + 1)
2155  continue;
2156 
2157  // If m_intrinsic_dim = 1, each point is output two times,
2158  // so we need to multiply each index by 2
2159  // And if only 2 vertices, add a third one (each vertex is duplicated in
2160  // the file when m_intrinsic dim = 2)
2161  if (m_intrinsic_dim == 1) {
2162  Simplex tmp_c;
2163  Simplex::iterator it = c.begin();
2164  for (; it != c.end(); ++it)
2165  tmp_c.insert(*it * 2);
2166  if (num_vertices == 2)
2167  tmp_c.insert(*tmp_c.rbegin() + 1);
2168 
2169  c = tmp_c;
2170  }
2171 
2172  if (num_vertices <= 3) {
2173  triangles.push_back(c);
2174  } else {
2175  // num_vertices >= 4: decompose the simplex in triangles
2176  std::vector<bool> booleans(num_vertices, false);
2177  std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
2178  do {
2179  Simplex triangle;
2180  Simplex::iterator it = c.begin();
2181  for (int i = 0; it != c.end(); ++i, ++it) {
2182  if (booleans[i])
2183  triangle.insert(*it);
2184  }
2185  triangles.push_back(triangle);
2186  } while (std::next_permutation(booleans.begin(), booleans.end()));
2187  }
2188 
2189  // For each cell
2190  Triangles::const_iterator it_tri = triangles.begin();
2191  Triangles::const_iterator it_tri_end = triangles.end();
2192  for (; it_tri != it_tri_end; ++it_tri) {
2193  // Don't export infinite cells
2194  if (is_infinite(*it_tri))
2195  continue;
2196 
2197  os << 3 << " ";
2198  Simplex::const_iterator it_point_idx = it_tri->begin();
2199  for (; it_point_idx != it_tri->end(); ++it_point_idx) {
2200  os << *it_point_idx << " ";
2201  }
2202 
2203  if (p_simpl_to_color_in_red || p_simpl_to_color_in_green
2204  || p_simpl_to_color_in_blue) {
2205  switch (color_simplex) {
2206  case 0: os << " 255 255 0";
2207  break;
2208  case 1: os << " 255 0 0";
2209  break;
2210  case 2: os << " 0 255 0";
2211  break;
2212  case 3: os << " 0 0 255";
2213  break;
2214  default: os << " 128 128 128";
2215  break;
2216  }
2217  }
2218 
2219  ++num_OFF_simplices;
2220  os << "\n";
2221  }
2222  }
2223 
2224 #ifdef DEBUG_TRACES
2225  std::cerr
2226  << "\n==========================================================\n"
2227  << "Export from complex to OFF:\n"
2228  << " * Number of vertices: " << m_points.size() << "\n"
2229  << " * Total number of maximal simplices: " << num_maximal_simplices
2230  << "\n"
2231  << "==========================================================\n";
2232 #endif
2233 
2234  return os;
2235  }
2236 
2237  private:
2238  const K m_k;
2239  const int m_intrinsic_dim;
2240  const int m_ambient_dim;
2241 
2242  Points m_points;
2243  Weights m_weights;
2244 #ifdef GUDHI_TC_PERTURB_POSITION
2245  Translations_for_perturb m_translations;
2246 #if defined(GUDHI_USE_TBB)
2247  Mutex_for_perturb *m_p_perturb_mutexes;
2248 #endif
2249 #endif
2250 
2251  Points_ds m_points_ds;
2252  double m_last_max_perturb;
2253  std::vector<bool> m_are_tangent_spaces_computed;
2254  TS_container m_tangent_spaces;
2255 #ifdef GUDHI_TC_EXPORT_NORMALS
2256  OS_container m_orth_spaces;
2257 #endif
2258  Tr_container m_triangulations; // Contains the triangulations
2259  // and their center vertex
2260  Stars_container m_stars;
2261  std::vector<FT> m_squared_star_spheres_radii_incl_margin;
2262 
2263 #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
2264  Points m_points_for_tse;
2265  Points_ds m_points_ds_for_tse;
2266 #endif
2267 
2268  mutable CGAL::Random m_random_generator;
2269 }; // /class Tangential_complex
2270 
2271 } // end namespace tangential_complex
2272 } // end namespace Gudhi
2273 
2274 #endif // TANGENTIAL_COMPLEX_H_
std::size_t num_inconsistent_simplices
Number of inconsistent simplices.
Definition: Tangential_complex.h:610
Type returned by Tangential_complex::fix_inconsistencies_using_perturbation.
Definition: Tangential_complex.h:419
Point get_point(std::size_t vertex) const
Returns the point corresponding to the vertex given as parameter.
Definition: Tangential_complex.h:322
Tangential complex data structure.
Definition: Tangential_complex.h:132
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:110
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:102
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:174
std::size_t final_num_inconsistent_stars
final number of inconsistent stars
Definition: Tangential_complex.h:429
Definition: SimplicialComplexForAlpha.h:26
~Tangential_complex()
Destructor.
Definition: Tangential_complex.h:297
std::size_t num_simplices
Total number of simplices in stars (including duplicates that appear in several stars) ...
Definition: Tangential_complex.h:608
std::size_t best_num_inconsistent_stars
best number of inconsistent stars during the process
Definition: Tangential_complex.h:427
std::size_t num_inconsistent_stars
Number of stars containing at least one inconsistent simplex.
Definition: Tangential_complex.h:612
int create_complex(Simplex_tree_ &tree, bool export_inconsistent_simplices=true) const
Exports the complex into a Simplex_tree.
Definition: Tangential_complex.h:682
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:437
std::size_t initial_num_inconsistent_stars
initial number of inconsistent stars
Definition: Tangential_complex.h:425
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:268
Num_inconsistencies number_of_inconsistent_simplices(bool verbose=false) const
Definition: Tangential_complex.h:619
bool success
true if all inconsistencies could be removed, false if the time limit has been reached before ...
Definition: Tangential_complex.h:421
int intrinsic_dimension() const
Returns the intrinsic dimension of the manifold.
Definition: Tangential_complex.h:304
Definition: Intro_spatial_searching.h:28
void compute_tangential_complex()
Computes the tangential complex.
Definition: Tangential_complex.h:369
int ambient_dimension() const
Returns the ambient dimension.
Definition: Tangential_complex.h:309
Type returned by Tangential_complex::number_of_inconsistent_simplices.
Definition: Tangential_complex.h:606
std::size_t number_of_vertices() const
Returns the number of vertices.
Definition: Tangential_complex.h:337
unsigned int num_steps
number of steps performed
Definition: Tangential_complex.h:423
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:331
GUDHI  Version 2.2.0  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : GPL v3 Generated on Thu Jun 14 2018 15:00:55 for GUDHI by Doxygen 1.8.13