Cech_complex_blocker.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): Vincent Rouvreau
4 *
5 * Copyright (C) 2018 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
11#ifndef CECH_COMPLEX_BLOCKER_H_
12#define CECH_COMPLEX_BLOCKER_H_
13
14#include <CGAL/NT_converter.h> // for casting from FT to Filtration_value
15#include <CGAL/Lazy_exact_nt.h> // for CGAL::exact
16
17#include <iostream>
18#include <vector>
19#include <set>
20#include <cmath> // for std::sqrt
21
22namespace Gudhi {
23
24namespace cech_complex {
25
42template <typename SimplicialComplexForCech, typename Cech_complex, typename Kernel>
43class Cech_blocker {
44
45 public:
46
47 using Point_d = typename Kernel::Point_d;
48 // Numeric type of coordinates in the kernel
49 using FT = typename Kernel::FT;
50 // Sphere is a pair of point and squared radius.
51 using Sphere = std::pair<Point_d, FT>;
52
53 private:
54
55 using Simplex_handle = typename SimplicialComplexForCech::Simplex_handle;
57 using Simplex_key = typename SimplicialComplexForCech::Simplex_key;
58
59 template<class PointIterator>
60 Sphere get_sphere(PointIterator begin, PointIterator end) const {
61 Point_d c = kernel_.construct_circumcenter_d_object()(begin, end);
62 FT r = kernel_.squared_distance_d_object()(c, *begin);
63 return std::make_pair(std::move(c), std::move(r));
64 }
65
66 public:
67
72 bool operator()(Simplex_handle sh) {
73 using Point_cloud = std::vector<Point_d>;
74 Filtration_value radius = 0;
75 bool is_min_enclos_ball = false;
76 Point_cloud points;
77 auto dim = sc_ptr_->dimension(sh);
78 if (dim > kernel_.point_dimension_d_object()(cc_ptr_->get_point(0))) {
79 // A sphere is always determined by at most d+1 points
80 return false;
81 }
82 points.reserve(dim + 1);
83
84 // for each face of simplex sh, test outsider point is indeed inside enclosing ball, if yes, take it and exit loop, otherwise, new sphere is circumsphere of all vertices
85 for (auto face_opposite_vertex : sc_ptr_->boundary_opposite_vertex_simplex_range(sh)) {
86 auto k = sc_ptr_->key(face_opposite_vertex.first);
87 Simplex_key sph_key;
88 if(k != sc_ptr_->null_key()) {
89 sph_key = k;
90 }
91 else {
92 for (auto vertex : sc_ptr_->simplex_vertex_range(face_opposite_vertex.first)) {
93 points.push_back(cc_ptr_->get_point(vertex));
94#ifdef DEBUG_TRACES
95 std::clog << "#(" << vertex << ")#";
96#endif // DEBUG_TRACES
97 }
98 // Put edge sphere in cache
99 sph_key = cc_ptr_->get_cache().size();
100 sc_ptr_->assign_key(face_opposite_vertex.first, sph_key);
101 cc_ptr_->get_cache().push_back(get_sphere(points.cbegin(), points.cend()));
102 // Clear face points
103 points.clear();
104 }
105 // Check if the minimal enclosing ball of current face contains the extra point/opposite vertex
106 Sphere const& sph = cc_ptr_->get_cache()[sph_key];
107 if (kernel_.squared_distance_d_object()(sph.first, cc_ptr_->get_point(face_opposite_vertex.second)) <= sph.second) {
108 is_min_enclos_ball = true;
109 sc_ptr_->assign_key(sh, sph_key);
110 radius = sc_ptr_->filtration(face_opposite_vertex.first);
111#ifdef DEBUG_TRACES
112 std::clog << "center: " << sph.first << ", radius: " << radius << std::endl;
113#endif // DEBUG_TRACES
114 break;
115 }
116 }
117 // Spheres of each face don't contain the whole simplex
118 if(!is_min_enclos_ball) {
119 for (auto vertex : sc_ptr_->simplex_vertex_range(sh)) {
120 points.push_back(cc_ptr_->get_point(vertex));
121 }
122 Sphere sph = get_sphere(points.cbegin(), points.cend());
123#if CGAL_VERSION_NR >= 1050000000
124 if(cc_ptr_->is_exact()) CGAL::exact(sph.second);
125#endif
126 CGAL::NT_converter<FT, Filtration_value> cast_to_fv;
127 radius = std::sqrt(cast_to_fv(sph.second));
128
129 sc_ptr_->assign_key(sh, cc_ptr_->get_cache().size());
130 cc_ptr_->get_cache().push_back(std::move(sph));
131 }
132
133#ifdef DEBUG_TRACES
134 if (radius > cc_ptr_->max_radius()) std::clog << "radius > max_radius => expansion is blocked\n";
135#endif // DEBUG_TRACES
136 // Check that the filtration to be assigned (radius) would be valid
137 if (radius > sc_ptr_->filtration(sh)) sc_ptr_->assign_filtration(sh, radius);
138 return (radius > cc_ptr_->max_radius());
139 }
140
142 Cech_blocker(SimplicialComplexForCech* sc_ptr, Cech_complex* cc_ptr) : sc_ptr_(sc_ptr), cc_ptr_(cc_ptr) {}
143
144 private:
145 SimplicialComplexForCech* sc_ptr_;
146 Cech_complex* cc_ptr_;
147 Kernel kernel_;
148};
149
150} // namespace cech_complex
151
152} // namespace Gudhi
153
154#endif // CECH_COMPLEX_BLOCKER_H_
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20
unspecified Filtration_value
Definition: SimplicialComplexForCech.h:27
unspecified Simplex_handle
Definition: SimplicialComplexForCech.h:23