From 8d7329f3e5ad843e553c3c5503cecc28ef2eead6 Mon Sep 17 00:00:00 2001 From: Gard Spreemann Date: Thu, 20 Apr 2017 11:10:45 +0200 Subject: GUDHI 2.0.0 as released by upstream in a tarball. --- include/gudhi/Active_witness/Active_witness.h | 67 + .../gudhi/Active_witness/Active_witness_iterator.h | 108 + include/gudhi/Alpha_complex.h | 233 +- include/gudhi/Alpha_complex.h~ | 417 ---- include/gudhi/Bottleneck.h | 115 + include/gudhi/Clock.h | 48 +- include/gudhi/Debug_utils.h | 2 + include/gudhi/Edge_contraction.h | 2 +- include/gudhi/Euclidean_strong_witness_complex.h | 104 + include/gudhi/Euclidean_witness_complex.h | 106 + include/gudhi/Graph_matching.h | 174 ++ include/gudhi/Internal_point.h | 91 + include/gudhi/Kd_tree_search.h | 264 +++ include/gudhi/Landmark_choice_by_furthest_point.h | 105 - include/gudhi/Landmark_choice_by_random_point.h | 96 - include/gudhi/Neighbors_finder.h | 192 ++ include/gudhi/Null_output_iterator.h | 48 + include/gudhi/Persistence_graph.h | 188 ++ include/gudhi/Persistent_cohomology.h | 26 +- include/gudhi/Points_3D_off_io.h | 4 +- include/gudhi/Points_off_io.h | 13 +- include/gudhi/Rips_complex.h | 185 ++ include/gudhi/Simplex_tree.h | 2 +- include/gudhi/Skeleton_blocker.h | 219 +- .../Skeleton_blocker_complex_visitor.h | 53 +- .../Skeleton_blocker_link_superior.h | 14 +- .../Skeleton_blocker/Skeleton_blocker_off_io.h | 11 +- .../Skeleton_blocker_simple_geometric_traits.h | 13 +- .../Skeleton_blocker_simple_traits.h | 38 +- .../Skeleton_blocker/Skeleton_blocker_simplex.h | 12 +- .../Skeleton_blocker_sub_complex.h | 49 +- .../gudhi/Skeleton_blocker/internal/Top_faces.h | 5 +- include/gudhi/Skeleton_blocker/internal/Trie.h | 9 +- .../Skeleton_blockers_blockers_iterators.h | 3 +- .../iterators/Skeleton_blockers_edges_iterators.h | 3 +- .../iterators/Skeleton_blockers_iterators.h | 2 +- .../Skeleton_blockers_simplices_iterators.h | 38 +- .../Skeleton_blockers_triangles_iterators.h | 14 +- .../Skeleton_blockers_vertices_iterators.h | 12 +- include/gudhi/Skeleton_blocker_complex.h | 33 +- include/gudhi/Skeleton_blocker_geometric_complex.h | 3 +- include/gudhi/Skeleton_blocker_link_complex.h | 30 +- .../gudhi/Skeleton_blocker_simplifiable_complex.h | 13 +- include/gudhi/Strong_witness_complex.h | 185 ++ include/gudhi/Tangential_complex.h | 2276 ++++++++++++++++++++ .../gudhi/Tangential_complex/Simplicial_complex.h | 539 +++++ include/gudhi/Tangential_complex/config.h | 43 + include/gudhi/Tangential_complex/utilities.h | 195 ++ include/gudhi/Test.h | 105 - include/gudhi/Witness_complex.h | 333 ++- include/gudhi/Witness_complex/all_faces_in.h | 55 + include/gudhi/choose_n_farthest_points.h | 133 ++ include/gudhi/console_color.h | 97 + include/gudhi/distance_functions.h | 40 +- include/gudhi/graph_simplicial_complex.h | 59 +- include/gudhi/pick_n_random_points.h | 86 + include/gudhi/random_point_generators.h | 474 ++++ include/gudhi/reader_utils.h | 166 +- include/gudhi/sparsify_point_set.h | 113 + .../Bottleneck_distance_CGAL_patches.txt | 3 + include/gudhi_patches/CGAL/Convex_hull.h | 56 + .../gudhi_patches/CGAL/Delaunay_triangulation.h | 933 ++++++++ include/gudhi_patches/CGAL/Epeck_d.h | 53 + include/gudhi_patches/CGAL/Epick_d.h | 71 + .../CGAL/IO/Triangulation_off_ostream.h | 320 +++ include/gudhi_patches/CGAL/Kd_tree.h | 582 +++++ include/gudhi_patches/CGAL/Kd_tree_node.h | 586 +++++ .../CGAL/NewKernel_d/Cartesian_LA_base.h | 177 ++ .../CGAL/NewKernel_d/Cartesian_LA_functors.h | 344 +++ .../CGAL/NewKernel_d/Cartesian_base.h | 40 + .../CGAL/NewKernel_d/Cartesian_change_FT.h | 117 + .../CGAL/NewKernel_d/Cartesian_complete.h | 33 + .../CGAL/NewKernel_d/Cartesian_filter_K.h | 79 + .../CGAL/NewKernel_d/Cartesian_filter_NT.h | 93 + .../CGAL/NewKernel_d/Cartesian_per_dimension.h | 33 + .../CGAL/NewKernel_d/Cartesian_static_filters.h | 95 + include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h | 330 +++ .../CGAL/NewKernel_d/Define_kernel_types.h | 50 + .../CGAL/NewKernel_d/Dimension_base.h | 49 + .../CGAL/NewKernel_d/Filtered_predicate2.h | 137 ++ .../CGAL/NewKernel_d/KernelD_converter.h | 199 ++ .../CGAL/NewKernel_d/Kernel_2_interface.h | 104 + .../CGAL/NewKernel_d/Kernel_3_interface.h | 102 + .../CGAL/NewKernel_d/Kernel_d_interface.h | 298 +++ .../CGAL/NewKernel_d/Kernel_object_converter.h | 134 ++ .../gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h | 175 ++ .../CGAL/NewKernel_d/LA_eigen/constructors.h | 162 ++ .../CGAL/NewKernel_d/Lazy_cartesian.h | 188 ++ .../CGAL/NewKernel_d/Types/Aff_transformation.h | 59 + .../CGAL/NewKernel_d/Types/Hyperplane.h | 159 ++ .../gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h | 88 + .../gudhi_patches/CGAL/NewKernel_d/Types/Line.h | 66 + include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h | 66 + .../gudhi_patches/CGAL/NewKernel_d/Types/Segment.h | 121 ++ .../gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h | 132 ++ .../CGAL/NewKernel_d/Types/Weighted_point.h | 205 ++ .../gudhi_patches/CGAL/NewKernel_d/Vector/array.h | 165 ++ .../gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h | 213 ++ ...f_iterator_to_points_from_iterator_to_vectors.h | 76 + ...determinant_of_iterator_to_points_from_points.h | 211 ++ ...terminant_of_iterator_to_vectors_from_vectors.h | 201 ++ .../Vector/determinant_of_points_from_vectors.h | 164 ++ .../Vector/determinant_of_vectors_small_dim.h | 58 + .../determinant_of_vectors_small_dim_internal.h | 164 ++ .../gudhi_patches/CGAL/NewKernel_d/Vector/mix.h | 46 + .../gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h | 145 ++ .../gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h | 181 ++ .../gudhi_patches/CGAL/NewKernel_d/Vector/vector.h | 167 ++ .../CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h | 305 +++ .../CGAL/NewKernel_d/Wrapper/Hyperplane_d.h | 131 ++ .../CGAL/NewKernel_d/Wrapper/Point_d.h | 284 +++ .../CGAL/NewKernel_d/Wrapper/Ref_count_obj.h | 120 ++ .../CGAL/NewKernel_d/Wrapper/Segment_d.h | 133 ++ .../CGAL/NewKernel_d/Wrapper/Sphere_d.h | 130 ++ .../CGAL/NewKernel_d/Wrapper/Vector_d.h | 266 +++ .../CGAL/NewKernel_d/Wrapper/Weighted_point_d.h | 129 ++ .../CGAL/NewKernel_d/function_objects_cartesian.h | 1355 ++++++++++++ .../CGAL/NewKernel_d/functor_properties.h | 40 + .../gudhi_patches/CGAL/NewKernel_d/functor_tags.h | 363 ++++ .../gudhi_patches/CGAL/NewKernel_d/static_int.h | 61 + .../gudhi_patches/CGAL/NewKernel_d/store_kernel.h | 104 + include/gudhi_patches/CGAL/NewKernel_d/utils.h | 306 +++ .../CGAL/Orthogonal_incremental_neighbor_search.h | 620 ++++++ include/gudhi_patches/CGAL/Regular_triangulation.h | 1169 ++++++++++ .../CGAL/Regular_triangulation_traits_adapter.h | 288 +++ .../CGAL/TDS_full_cell_default_storage_policy.h | 99 + .../CGAL/TDS_full_cell_mirror_storage_policy.h | 71 + include/gudhi_patches/CGAL/Triangulation.h | 1424 ++++++++++++ .../CGAL/Triangulation_data_structure.h | 1603 ++++++++++++++ .../CGAL/Triangulation_ds_full_cell.h | 311 +++ .../gudhi_patches/CGAL/Triangulation_ds_vertex.h | 154 ++ include/gudhi_patches/CGAL/Triangulation_face.h | 111 + .../gudhi_patches/CGAL/Triangulation_full_cell.h | 148 ++ include/gudhi_patches/CGAL/Triangulation_vertex.h | 128 ++ include/gudhi_patches/CGAL/argument_swaps.h | 88 + .../gudhi_patches/CGAL/determinant_of_vectors.h | 117 + .../CGAL/internal/Combination_enumerator.h | 148 ++ .../CGAL/internal/Static_or_dynamic_array.h | 116 + .../CGAL/internal/Triangulation/Dummy_TDS.h | 49 + .../Triangulation/Triangulation_ds_iterators.h | 154 ++ .../CGAL/internal/Triangulation/utilities.h | 154 ++ include/gudhi_patches/CGAL/iterator_from_indices.h | 75 + include/gudhi_patches/CGAL/transforming_iterator.h | 123 ++ .../CGAL/transforming_pair_iterator.h | 127 ++ include/gudhi_patches/CGAL/typeset.h | 117 + .../Tangential_complex_CGAL_patches.txt | 82 + 146 files changed, 26039 insertions(+), 1457 deletions(-) create mode 100644 include/gudhi/Active_witness/Active_witness.h create mode 100644 include/gudhi/Active_witness/Active_witness_iterator.h delete mode 100644 include/gudhi/Alpha_complex.h~ create mode 100644 include/gudhi/Bottleneck.h create mode 100644 include/gudhi/Euclidean_strong_witness_complex.h create mode 100644 include/gudhi/Euclidean_witness_complex.h create mode 100644 include/gudhi/Graph_matching.h create mode 100644 include/gudhi/Internal_point.h create mode 100644 include/gudhi/Kd_tree_search.h delete mode 100644 include/gudhi/Landmark_choice_by_furthest_point.h delete mode 100644 include/gudhi/Landmark_choice_by_random_point.h create mode 100644 include/gudhi/Neighbors_finder.h create mode 100644 include/gudhi/Null_output_iterator.h create mode 100644 include/gudhi/Persistence_graph.h create mode 100644 include/gudhi/Rips_complex.h create mode 100644 include/gudhi/Strong_witness_complex.h create mode 100644 include/gudhi/Tangential_complex.h create mode 100644 include/gudhi/Tangential_complex/Simplicial_complex.h create mode 100644 include/gudhi/Tangential_complex/config.h create mode 100644 include/gudhi/Tangential_complex/utilities.h delete mode 100644 include/gudhi/Test.h create mode 100644 include/gudhi/Witness_complex/all_faces_in.h create mode 100644 include/gudhi/choose_n_farthest_points.h create mode 100644 include/gudhi/console_color.h create mode 100644 include/gudhi/pick_n_random_points.h create mode 100644 include/gudhi/random_point_generators.h create mode 100644 include/gudhi/sparsify_point_set.h create mode 100644 include/gudhi_patches/Bottleneck_distance_CGAL_patches.txt create mode 100644 include/gudhi_patches/CGAL/Convex_hull.h create mode 100644 include/gudhi_patches/CGAL/Delaunay_triangulation.h create mode 100644 include/gudhi_patches/CGAL/Epeck_d.h create mode 100644 include/gudhi_patches/CGAL/Epick_d.h create mode 100644 include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h create mode 100644 include/gudhi_patches/CGAL/Kd_tree.h create mode 100644 include/gudhi_patches/CGAL/Kd_tree_node.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Define_kernel_types.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Dimension_base.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Filtered_predicate2.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/static_int.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h create mode 100644 include/gudhi_patches/CGAL/NewKernel_d/utils.h create mode 100644 include/gudhi_patches/CGAL/Orthogonal_incremental_neighbor_search.h create mode 100644 include/gudhi_patches/CGAL/Regular_triangulation.h create mode 100644 include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h create mode 100644 include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h create mode 100644 include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h create mode 100644 include/gudhi_patches/CGAL/Triangulation.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_data_structure.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_ds_vertex.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_face.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_full_cell.h create mode 100644 include/gudhi_patches/CGAL/Triangulation_vertex.h create mode 100644 include/gudhi_patches/CGAL/argument_swaps.h create mode 100644 include/gudhi_patches/CGAL/determinant_of_vectors.h create mode 100644 include/gudhi_patches/CGAL/internal/Combination_enumerator.h create mode 100644 include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h create mode 100644 include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h create mode 100644 include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h create mode 100644 include/gudhi_patches/CGAL/internal/Triangulation/utilities.h create mode 100644 include/gudhi_patches/CGAL/iterator_from_indices.h create mode 100644 include/gudhi_patches/CGAL/transforming_iterator.h create mode 100644 include/gudhi_patches/CGAL/transforming_pair_iterator.h create mode 100644 include/gudhi_patches/CGAL/typeset.h create mode 100644 include/gudhi_patches/Tangential_complex_CGAL_patches.txt (limited to 'include') diff --git a/include/gudhi/Active_witness/Active_witness.h b/include/gudhi/Active_witness/Active_witness.h new file mode 100644 index 00000000..d41a6811 --- /dev/null +++ b/include/gudhi/Active_witness/Active_witness.h @@ -0,0 +1,67 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2016 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ACTIVE_WITNESS_ACTIVE_WITNESS_H_ +#define ACTIVE_WITNESS_ACTIVE_WITNESS_H_ + +#include +#include + +namespace Gudhi { + +namespace witness_complex { + + /* \class Active_witness + * \brief Class representing a list of nearest neighbors to a given witness. + * \details Every element is a pair of a landmark identifier and the squared distance to it. + */ +template< typename Id_distance_pair, + typename INS_range > +class Active_witness { + public: + typedef Active_witness ActiveWitness; + typedef typename INS_range::iterator INS_iterator; + typedef Active_witness_iterator< ActiveWitness, Id_distance_pair, INS_iterator > iterator; + typedef typename std::list Table; + + Table nearest_landmark_table_; + INS_range search_range_; + INS_iterator iterator_next_; + INS_iterator iterator_end_; + + Active_witness(const INS_range& search_range) + : search_range_(search_range), iterator_next_(search_range_.begin()), iterator_end_(search_range_.end()) { + } + + iterator begin() { + return iterator(this, nearest_landmark_table_.begin()); + } + + iterator end() { + return iterator(this); + } +}; + +} // namespace witness_complex +} // namespace Gudhi + +#endif // ACTIVE_WITNESS_ACTIVE_WITNESS_H_ diff --git a/include/gudhi/Active_witness/Active_witness_iterator.h b/include/gudhi/Active_witness/Active_witness_iterator.h new file mode 100644 index 00000000..0a05173a --- /dev/null +++ b/include/gudhi/Active_witness/Active_witness_iterator.h @@ -0,0 +1,108 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2016 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_ +#define ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_ + +#include +#include + +namespace Gudhi { + +namespace witness_complex { + +/* \brief Iterator in the nearest landmark list. + * \details After the iterator reaches the end of the list, + * the list is augmented by a (nearest landmark, distance) pair if possible. + * If all the landmarks are present in the list, iterator returns the specific end value + * of the corresponding 'Active_witness' object. + */ +template< typename Active_witness, + typename Id_distance_pair, + typename INS_iterator > +class Active_witness_iterator + : public boost::iterator_facade< Active_witness_iterator , + Id_distance_pair const, + boost::forward_traversal_tag, + Id_distance_pair const> { + friend class boost::iterator_core_access; + + typedef typename std::list::iterator Pair_iterator; + typedef typename Gudhi::witness_complex::Active_witness_iterator Iterator; + + Active_witness *aw_; + Pair_iterator lh_; // landmark handle + bool is_end_; // true only if the pointer is end and there are no more neighbors to add + + public: + Active_witness_iterator(Active_witness* aw) + : aw_(aw), lh_(aw_->nearest_landmark_table_.end()), is_end_(true) { + } + + Active_witness_iterator(Active_witness* aw, const Pair_iterator& lh) + : aw_(aw), lh_(lh) { + is_end_ = false; + if (lh_ == aw_->nearest_landmark_table_.end()) { + if (aw_->iterator_next_ == aw_->iterator_end_) { + is_end_ = true; + } else { + aw_->nearest_landmark_table_.push_back(*aw_->iterator_next_); + lh_ = --aw_->nearest_landmark_table_.end(); + ++(aw_->iterator_next_); + } + } + } + + private : + Id_distance_pair& dereference() const { + return *lh_; + } + + bool equal(const Iterator& other) const { + return (is_end_ == other.is_end_) || (lh_ == other.lh_); + } + + void increment() { + // the neighbor search can't be at the end iterator of a list + GUDHI_CHECK(!is_end_ && lh_ != aw_->nearest_landmark_table_.end(), + std::logic_error("Wrong active witness increment.")); + // if the id of the current landmark is the same as the last one + + lh_++; + if (lh_ == aw_->nearest_landmark_table_.end()) { + if (aw_->iterator_next_ == aw_->iterator_end_) { + is_end_ = true; + } else { + aw_->nearest_landmark_table_.push_back(*aw_->iterator_next_); + lh_ = std::prev(aw_->nearest_landmark_table_.end()); + ++(aw_->iterator_next_); + } + } + } +}; + +} // namespace witness_complex +} // namespace Gudhi + +#endif // ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_ diff --git a/include/gudhi/Alpha_complex.h b/include/gudhi/Alpha_complex.h index 2c95ceb4..1ff95c3d 100644 --- a/include/gudhi/Alpha_complex.h +++ b/include/gudhi/Alpha_complex.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2015 INRIA Saclay (France) + * Copyright (C) 2015 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +23,6 @@ #ifndef ALPHA_COMPLEX_H_ #define ALPHA_COMPLEX_H_ -// to construct a simplex_tree from Delaunay_triangulation -#include -#include #include // to construct Alpha_complex from a OFF file of points #include @@ -36,6 +33,7 @@ #include #include #include +#include // for CGAL::Identity_property_map #include #include @@ -57,9 +55,9 @@ namespace alpha_complex { * \ingroup alpha_complex * * \details - * The data structure can be constructed from a CGAL Delaunay triangulation (for more informations on CGAL Delaunay - * triangulation, please refer to the corresponding chapter in page http://doc.cgal.org/latest/Triangulation/) or from - * an OFF file (cf. Points_off_reader). + * The data structure is constructing a CGAL Delaunay triangulation (for more informations on CGAL Delaunay + * triangulation, please refer to the corresponding chapter in page http://doc.cgal.org/latest/Triangulation/) from a + * range of points or from an OFF file (cf. Points_off_reader). * * Please refer to \ref alpha_complex for examples. * @@ -74,7 +72,7 @@ namespace alpha_complex { * */ template> -class Alpha_complex : public Simplex_tree<> { +class Alpha_complex { public: // Add an int in TDS to save point index in the structure typedef CGAL::Triangulation_data_structure { typedef Kernel Geom_traits; private: - // From Simplex_tree - // Type required to insert into a simplex_tree (with or without subfaces). - typedef std::vector Vector_vertex; - - // Simplex_result is the type returned from simplex_tree insert function. - typedef typename std::pair Simplex_result; - typedef typename Kernel::Compute_squared_radius_d Squared_Radius; typedef typename Kernel::Side_of_bounded_sphere_d Is_Gabriel; typedef typename Kernel::Point_dimension_d Point_Dimension; @@ -111,7 +102,7 @@ class Alpha_complex : public Simplex_tree<> { typedef typename Delaunay_triangulation::size_type size_type; // Map type to switch from simplex tree vertex handle to CGAL vertex iterator. - typedef typename std::map< Vertex_handle, CGAL_vertex_iterator > Vector_vertex_iterator; + typedef typename std::map< std::size_t, CGAL_vertex_iterator > Vector_vertex_iterator; private: /** \brief Vertex iterator vector to switch from simplex tree vertex handle to CGAL vertex iterator. @@ -124,16 +115,15 @@ class Alpha_complex : public Simplex_tree<> { public: /** \brief Alpha_complex constructor from an OFF file name. - * Uses the Delaunay_triangulation_off_reader to construct the Delaunay triangulation required to initialize + * + * Uses the Points_off_reader to construct the Delaunay triangulation required to initialize * the Alpha_complex. * * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous. * * @param[in] off_file_name OFF file [path and] name. - * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$. */ - Alpha_complex(const std::string& off_file_name, - Filtration_value max_alpha_square = std::numeric_limits::infinity()) + Alpha_complex(const std::string& off_file_name) : triangulation_(nullptr) { Gudhi::Points_off_reader off_reader(off_file_name); if (!off_reader.is_valid()) { @@ -141,7 +131,7 @@ class Alpha_complex : public Simplex_tree<> { exit(-1); // ----- >> } - init_from_range(off_reader.get_point_cloud(), max_alpha_square); + init_from_range(off_reader.get_point_cloud()); } /** \brief Alpha_complex constructor from a list of points. @@ -149,23 +139,17 @@ class Alpha_complex : public Simplex_tree<> { * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous. * * @param[in] points Range of points to triangulate. Points must be in Kernel::Point_d - * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$. * * The type InputPointRange must be a range for which std::begin and * std::end return input iterators on a Kernel::Point_d. - * - * @post Compare num_simplices with InputPointRange points number (not the same in case of duplicate points). */ template - Alpha_complex(const InputPointRange& points, - Filtration_value max_alpha_square = std::numeric_limits::infinity()) + Alpha_complex(const InputPointRange& points) : triangulation_(nullptr) { - init_from_range(points, max_alpha_square); + init_from_range(points); } - /** \brief Alpha_complex destructor. - * - * @warning Deletes the Delaunay triangulation. + /** \brief Alpha_complex destructor deletes the Delaunay triangulation. */ ~Alpha_complex() { delete triangulation_; @@ -183,15 +167,24 @@ class Alpha_complex : public Simplex_tree<> { * @return The point found. * @exception std::out_of_range In case vertex is not found (cf. std::vector::at). */ - Point_d get_point(Vertex_handle vertex) const { + const Point_d& get_point(std::size_t vertex) const { return vertex_handle_to_iterator_.at(vertex)->point(); } + /** \brief number_of_vertices returns the number of vertices (same as the number of points). + * + * @return The number of vertices. + */ + const std::size_t number_of_vertices() const { + return vertex_handle_to_iterator_.size(); + } + private: template - void init_from_range(const InputPointRange& points, Filtration_value max_alpha_square) { + void init_from_range(const InputPointRange& points) { auto first = std::begin(points); auto last = std::end(points); + if (first != last) { // point_dimension function initialization Point_Dimension point_dimension = kernel_.point_dimension_d_object(); @@ -199,90 +192,107 @@ class Alpha_complex : public Simplex_tree<> { // Delaunay triangulation is point dimension. triangulation_ = new Delaunay_triangulation(point_dimension(*first)); - std::vector points(first, last); + std::vector point_cloud(first, last); // Creates a vector {0, 1, ..., N-1} std::vector indices(boost::counting_iterator(0), - boost::counting_iterator(points.size())); + boost::counting_iterator(point_cloud.size())); + + typedef boost::iterator_property_map::iterator, + CGAL::Identity_property_map> Point_property_map; + typedef CGAL::Spatial_sort_traits_adapter_d Search_traits_d; - // Sort indices considering CGAL spatial sort - typedef CGAL::Spatial_sort_traits_adapter_d Search_traits_d; - spatial_sort(indices.begin(), indices.end(), Search_traits_d(&(points[0]))); + CGAL::spatial_sort(indices.begin(), indices.end(), Search_traits_d(std::begin(point_cloud))); typename Delaunay_triangulation::Full_cell_handle hint; for (auto index : indices) { - typename Delaunay_triangulation::Vertex_handle pos = triangulation_->insert(points[index], hint); + typename Delaunay_triangulation::Vertex_handle pos = triangulation_->insert(point_cloud[index], hint); // Save index value as data to retrieve it after insertion pos->data() = index; hint = pos->full_cell(); } - init(max_alpha_square); + // -------------------------------------------------------------------------------------------- + // double map to retrieve simplex tree vertex handles from CGAL vertex iterator and vice versa + // Loop on triangulation vertices list + for (CGAL_vertex_iterator vit = triangulation_->vertices_begin(); vit != triangulation_->vertices_end(); ++vit) { + if (!triangulation_->is_infinite(*vit)) { +#ifdef DEBUG_TRACES + std::cout << "Vertex insertion - " << vit->data() << " -> " << vit->point() << std::endl; +#endif // DEBUG_TRACES + vertex_handle_to_iterator_.emplace(vit->data(), vit); + } + } + // -------------------------------------------------------------------------------------------- } } - /** \brief Initialize the Alpha_complex from the Delaunay triangulation. + public: + template + bool create_complex(SimplicialComplexForAlpha& complex) { + typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value; + return create_complex(complex, std::numeric_limits::infinity()); + } + + /** \brief Inserts all Delaunay triangulation into the simplicial complex. + * It also computes the filtration values accordingly to the \ref createcomplexalgorithm * - * @param[in] max_alpha_square maximum for alpha square value. + * \tparam SimplicialComplexForAlpha must meet `SimplicialComplexForAlpha` concept. * - * @warning Delaunay triangulation must be already constructed with at least one vertex and dimension must be more - * than 0. + * @param[in] complex SimplicialComplexForAlpha to be created. + * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$. + * + * @return true if creation succeeds, false otherwise. + * + * @pre Delaunay triangulation must be already constructed with dimension strictly greater than 0. + * @pre The simplicial complex must be empty (no vertices) * * Initialization can be launched once. */ - void init(Filtration_value max_alpha_square) { + template + bool create_complex(SimplicialComplexForAlpha& complex, Filtration_value max_alpha_square) { + // From SimplicialComplexForAlpha type required to insert into a simplicial complex (with or without subfaces). + typedef typename SimplicialComplexForAlpha::Vertex_handle Vertex_handle; + typedef typename SimplicialComplexForAlpha::Simplex_handle Simplex_handle; + typedef std::vector Vector_vertex; + if (triangulation_ == nullptr) { - std::cerr << "Alpha_complex init - Cannot init from a NULL triangulation\n"; - return; // ----- >> - } - if (triangulation_->number_of_vertices() < 1) { - std::cerr << "Alpha_complex init - Cannot init from a triangulation without vertices\n"; - return; // ----- >> + std::cerr << "Alpha_complex cannot create_complex from a NULL triangulation\n"; + return false; // ----- >> } if (triangulation_->maximal_dimension() < 1) { - std::cerr << "Alpha_complex init - Cannot init from a zero-dimension triangulation\n"; - return; // ----- >> + std::cerr << "Alpha_complex cannot create_complex from a zero-dimension triangulation\n"; + return false; // ----- >> } - if (num_vertices() > 0) { - std::cerr << "Alpha_complex init - Cannot init twice\n"; - return; // ----- >> + if (complex.num_vertices() > 0) { + std::cerr << "Alpha_complex create_complex - complex is not empty\n"; + return false; // ----- >> } - set_dimension(triangulation_->maximal_dimension()); - - // -------------------------------------------------------------------------------------------- - // double map to retrieve simplex tree vertex handles from CGAL vertex iterator and vice versa - // Loop on triangulation vertices list - for (CGAL_vertex_iterator vit = triangulation_->vertices_begin(); vit != triangulation_->vertices_end(); ++vit) { - if (!triangulation_->is_infinite(*vit)) { -#ifdef DEBUG_TRACES - std::cout << "Vertex insertion - " << vit->data() << " -> " << vit->point() << std::endl; -#endif // DEBUG_TRACES - vertex_handle_to_iterator_.emplace(vit->data(), vit); - } - } - // -------------------------------------------------------------------------------------------- + complex.set_dimension(triangulation_->maximal_dimension()); // -------------------------------------------------------------------------------------------- // Simplex_tree construction from loop on triangulation finite full cells list - for (auto cit = triangulation_->finite_full_cells_begin(); cit != triangulation_->finite_full_cells_end(); ++cit) { - Vector_vertex vertexVector; + if (triangulation_->number_of_vertices() > 0) { + for (auto cit = triangulation_->finite_full_cells_begin(); cit != triangulation_->finite_full_cells_end(); ++cit) { + Vector_vertex vertexVector; #ifdef DEBUG_TRACES - std::cout << "Simplex_tree insertion "; + std::cout << "Simplex_tree insertion "; #endif // DEBUG_TRACES - for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) { - if (*vit != nullptr) { + for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) { + if (*vit != nullptr) { #ifdef DEBUG_TRACES - std::cout << " " << (*vit)->data(); + std::cout << " " << (*vit)->data(); #endif // DEBUG_TRACES - // Vector of vertex construction for simplex_tree structure - vertexVector.push_back((*vit)->data()); + // Vector of vertex construction for simplex_tree structure + vertexVector.push_back((*vit)->data()); + } } - } #ifdef DEBUG_TRACES - std::cout << std::endl; + std::cout << std::endl; #endif // DEBUG_TRACES - // Insert each simplex and its subfaces in the simplex tree - filtration is NaN - insert_simplex_and_subfaces(vertexVector, std::numeric_limits::quiet_NaN()); + // Insert each simplex and its subfaces in the simplex tree - filtration is NaN + complex.insert_simplex_and_subfaces(vertexVector, std::numeric_limits::quiet_NaN()); + } } // -------------------------------------------------------------------------------------------- @@ -290,16 +300,16 @@ class Alpha_complex : public Simplex_tree<> { // Will be re-used many times Vector_of_CGAL_points pointVector; // ### For i : d -> 0 - for (int decr_dim = dimension(); decr_dim >= 0; decr_dim--) { + for (int decr_dim = triangulation_->maximal_dimension(); decr_dim >= 0; decr_dim--) { // ### Foreach Sigma of dim i - for (auto f_simplex : skeleton_simplex_range(decr_dim)) { - int f_simplex_dim = dimension(f_simplex); + for (Simplex_handle f_simplex : complex.skeleton_simplex_range(decr_dim)) { + int f_simplex_dim = complex.dimension(f_simplex); if (decr_dim == f_simplex_dim) { pointVector.clear(); #ifdef DEBUG_TRACES std::cout << "Sigma of dim " << decr_dim << " is"; #endif // DEBUG_TRACES - for (auto vertex : simplex_vertex_range(f_simplex)) { + for (auto vertex : complex.simplex_vertex_range(f_simplex)) { pointVector.push_back(get_point(vertex)); #ifdef DEBUG_TRACES std::cout << " " << vertex; @@ -309,7 +319,7 @@ class Alpha_complex : public Simplex_tree<> { std::cout << std::endl; #endif // DEBUG_TRACES // ### If filt(Sigma) is NaN : filt(Sigma) = alpha(Sigma) - if (std::isnan(filtration(f_simplex))) { + if (std::isnan(complex.filtration(f_simplex))) { Filtration_value alpha_complex_filtration = 0.0; // No need to compute squared_radius on a single point - alpha is 0.0 if (f_simplex_dim > 0) { @@ -318,12 +328,12 @@ class Alpha_complex : public Simplex_tree<> { alpha_complex_filtration = squared_radius(pointVector.begin(), pointVector.end()); } - assign_filtration(f_simplex, alpha_complex_filtration); + complex.assign_filtration(f_simplex, alpha_complex_filtration); #ifdef DEBUG_TRACES - std::cout << "filt(Sigma) is NaN : filt(Sigma) =" << filtration(f_simplex) << std::endl; + std::cout << "filt(Sigma) is NaN : filt(Sigma) =" << complex.filtration(f_simplex) << std::endl; #endif // DEBUG_TRACES } - propagate_alpha_filtration(f_simplex, decr_dim); + propagate_alpha_filtration(complex, f_simplex, decr_dim); } } } @@ -331,36 +341,41 @@ class Alpha_complex : public Simplex_tree<> { // -------------------------------------------------------------------------------------------- // As Alpha value is an approximation, we have to make filtration non decreasing while increasing the dimension - bool modified_filt = make_filtration_non_decreasing(); + complex.make_filtration_non_decreasing(); // Remove all simplices that have a filtration value greater than max_alpha_square - // Remark: prune_above_filtration does not require initialize_filtration to be done before. - modified_filt |= prune_above_filtration(max_alpha_square); - if (modified_filt) { - initialize_filtration(); - } + complex.prune_above_filtration(max_alpha_square); // -------------------------------------------------------------------------------------------- + return true; } - template - void propagate_alpha_filtration(Simplex_handle f_simplex, int decr_dim) { + private: + template + void propagate_alpha_filtration(SimplicialComplexForAlpha& complex, Simplex_handle f_simplex, int decr_dim) { + // From SimplicialComplexForAlpha type required to assign filtration values. + typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value; +#ifdef DEBUG_TRACES + typedef typename SimplicialComplexForAlpha::Vertex_handle Vertex_handle; +#endif // DEBUG_TRACES + // ### Foreach Tau face of Sigma - for (auto f_boundary : boundary_simplex_range(f_simplex)) { + for (auto f_boundary : complex.boundary_simplex_range(f_simplex)) { #ifdef DEBUG_TRACES std::cout << " | --------------------------------------------------\n"; std::cout << " | Tau "; - for (auto vertex : simplex_vertex_range(f_boundary)) { + for (auto vertex : complex.simplex_vertex_range(f_boundary)) { std::cout << vertex << " "; } std::cout << "is a face of Sigma\n"; - std::cout << " | isnan(filtration(Tau)=" << std::isnan(filtration(f_boundary)) << std::endl; + std::cout << " | isnan(complex.filtration(Tau)=" << std::isnan(complex.filtration(f_boundary)) << std::endl; #endif // DEBUG_TRACES // ### If filt(Tau) is not NaN - if (!std::isnan(filtration(f_boundary))) { + if (!std::isnan(complex.filtration(f_boundary))) { // ### filt(Tau) = fmin(filt(Tau), filt(Sigma)) - Filtration_value alpha_complex_filtration = fmin(filtration(f_boundary), filtration(f_simplex)); - assign_filtration(f_boundary, alpha_complex_filtration); + Filtration_value alpha_complex_filtration = fmin(complex.filtration(f_boundary), + complex.filtration(f_simplex)); + complex.assign_filtration(f_boundary, alpha_complex_filtration); #ifdef DEBUG_TRACES - std::cout << " | filt(Tau) = fmin(filt(Tau), filt(Sigma)) = " << filtration(f_boundary) << std::endl; + std::cout << " | filt(Tau) = fmin(filt(Tau), filt(Sigma)) = " << complex.filtration(f_boundary) << std::endl; #endif // DEBUG_TRACES // ### Else } else { @@ -372,12 +387,12 @@ class Alpha_complex : public Simplex_tree<> { #ifdef DEBUG_TRACES Vertex_handle vertexForGabriel = Vertex_handle(); #endif // DEBUG_TRACES - for (auto vertex : simplex_vertex_range(f_boundary)) { + for (auto vertex : complex.simplex_vertex_range(f_boundary)) { pointVector.push_back(get_point(vertex)); } // Retrieve the Sigma point that is not part of Tau - parameter for is_gabriel function Point_d point_for_gabriel; - for (auto vertex : simplex_vertex_range(f_simplex)) { + for (auto vertex : complex.simplex_vertex_range(f_simplex)) { point_for_gabriel = get_point(vertex); if (std::find(pointVector.begin(), pointVector.end(), point_for_gabriel) == pointVector.end()) { #ifdef DEBUG_TRACES @@ -398,10 +413,10 @@ class Alpha_complex : public Simplex_tree<> { // ### If Tau is not Gabriel of Sigma if (false == is_gab) { // ### filt(Tau) = filt(Sigma) - Filtration_value alpha_complex_filtration = filtration(f_simplex); - assign_filtration(f_boundary, alpha_complex_filtration); + Filtration_value alpha_complex_filtration = complex.filtration(f_simplex); + complex.assign_filtration(f_boundary, alpha_complex_filtration); #ifdef DEBUG_TRACES - std::cout << " | filt(Tau) = filt(Sigma) = " << filtration(f_boundary) << std::endl; + std::cout << " | filt(Tau) = filt(Sigma) = " << complex.filtration(f_boundary) << std::endl; #endif // DEBUG_TRACES } } diff --git a/include/gudhi/Alpha_complex.h~ b/include/gudhi/Alpha_complex.h~ deleted file mode 100644 index a1900cb9..00000000 --- a/include/gudhi/Alpha_complex.h~ +++ /dev/null @@ -1,417 +0,0 @@ -/* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * - * Author(s): Vincent Rouvreau - * - * Copyright (C) 2015 INRIA Saclay (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ALPHA_COMPLEX_H_ -#define ALPHA_COMPLEX_H_ - -// to construct a simplex_tree from Delaunay_triangulation -#include -#include -#include -// to construct Alpha_complex from a OFF file of points -#include - -#include -#include // isnan, fmax - -#include -#include -#include - -#include -#include -#include -#include // NaN -#include -#include // std::pair -#include -#include // for std::iota - -namespace Gudhi { - -namespace alphacomplex { - -/** - * \class Alpha_complex Alpha_complex.h gudhi/Alpha_complex.h - * \brief Alpha complex data structure. - * - * \ingroup alpha_complex - * - * \details - * The data structure can be constructed from a CGAL Delaunay triangulation (for more informations on CGAL Delaunay - * triangulation, please refer to the corresponding chapter in page http://doc.cgal.org/latest/Triangulation/) or from - * an OFF file (cf. Points_off_reader). - * - * Please refer to \ref alpha_complex for examples. - * - * The complex is a template class requiring an Epick_d dD Geometry Kernel - * \cite cgal:s-gkd-15b from CGAL as template, default value is CGAL::Epick_d - * < - * CGAL::Dynamic_dimension_tag > - * - * \remark When Alpha_complex is constructed with an infinite value of alpha, the complex is a Delaunay complex. - * - */ -template> -class Alpha_complex : public Simplex_tree<> { - public: - // Add an int in TDS to save point index in the structure - typedef CGAL::Triangulation_data_structure, - CGAL::Triangulation_full_cell > TDS; - /** \brief A Delaunay triangulation of a set of points in \f$ \mathbb{R}^D\f$.*/ - typedef CGAL::Delaunay_triangulation Delaunay_triangulation; - - /** \brief A point in Euclidean space.*/ - typedef typename Kernel::Point_d Point_d; - /** \brief Geometric traits class that provides the geometric types and predicates needed by Delaunay - * triangulations.*/ - typedef Kernel Geom_traits; - - private: - // From Simplex_tree - // Type required to insert into a simplex_tree (with or without subfaces). - typedef std::vector Vector_vertex; - - // Simplex_result is the type returned from simplex_tree insert function. - typedef typename std::pair Simplex_result; - - typedef typename Kernel::Compute_squared_radius_d Squared_Radius; - typedef typename Kernel::Side_of_bounded_sphere_d Is_Gabriel; - typedef typename Kernel::Point_dimension_d Point_Dimension; - - // Type required to compute squared radius, or side of bounded sphere on a vector of points. - typedef typename std::vector Vector_of_CGAL_points; - - // Vertex_iterator type from CGAL. - typedef typename Delaunay_triangulation::Vertex_iterator CGAL_vertex_iterator; - - // size_type type from CGAL. - typedef typename Delaunay_triangulation::size_type size_type; - - // Map type to switch from simplex tree vertex handle to CGAL vertex iterator. - typedef typename std::map< Vertex_handle, CGAL_vertex_iterator > Vector_vertex_iterator; - - private: - /** \brief Vertex iterator vector to switch from simplex tree vertex handle to CGAL vertex iterator. - * Vertex handles are inserted sequentially, starting at 0.*/ - Vector_vertex_iterator vertex_handle_to_iterator_; - /** \brief Pointer on the CGAL Delaunay triangulation.*/ - Delaunay_triangulation* triangulation_; - /** \brief Kernel for triangulation_ functions access.*/ - Kernel kernel_; - - public: - /** \brief Alpha_complex constructor from an OFF file name. - * Uses the Delaunay_triangulation_off_reader to construct the Delaunay triangulation required to initialize - * the Alpha_complex. - * - * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous. - * - * @param[in] off_file_name OFF file [path and] name. - * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$. - */ - Alpha_complex(const std::string& off_file_name, - Filtration_value max_alpha_square = std::numeric_limits::infinity()) - : triangulation_(nullptr) { - Gudhi::Points_off_reader off_reader(off_file_name); - if (!off_reader.is_valid()) { - std::cerr << "Alpha_complex - Unable to read file " << off_file_name << "\n"; - exit(-1); // ----- >> - } - - init_from_range(off_reader.get_point_cloud(), max_alpha_square); - } - - /** \brief Alpha_complex constructor from a list of points. - * - * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous. - * - * @param[in] points Range of points to triangulate. Points must be in Kernel::Point_d - * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$. - * - * The type InputPointRange must be a range for which std::begin and - * std::end return input iterators on a Kernel::Point_d. - * - * @post Compare num_simplices with InputPointRange points number (not the same in case of duplicate points). - */ - template - Alpha_complex(const InputPointRange& points, - Filtration_value max_alpha_square = std::numeric_limits::infinity()) - : triangulation_(nullptr) { - init_from_range(points, max_alpha_square); - } - - /** \brief Alpha_complex destructor. - * - * @warning Deletes the Delaunay triangulation. - */ - ~Alpha_complex() { - delete triangulation_; - } - - // Forbid copy/move constructor/assignment operator - Alpha_complex(const Alpha_complex& other) = delete; - Alpha_complex& operator= (const Alpha_complex& other) = delete; - Alpha_complex (Alpha_complex&& other) = delete; - Alpha_complex& operator= (Alpha_complex&& other) = delete; - - /** \brief get_point returns the point corresponding to the vertex given as parameter. - * - * @param[in] vertex Vertex handle of the point to retrieve. - * @return The point found. - * @exception std::out_of_range In case vertex is not found (cf. std::vector::at). - */ - Point_d get_point(Vertex_handle vertex) const { - return vertex_handle_to_iterator_.at(vertex)->point(); - } - - private: - template - void init_from_range(const InputPointRange& points, Filtration_value max_alpha_square) { - auto first = std::begin(points); - auto last = std::end(points); - if (first != last) { - // point_dimension function initialization - Point_Dimension point_dimension = kernel_.point_dimension_d_object(); - - // Delaunay triangulation is point dimension. - triangulation_ = new Delaunay_triangulation(point_dimension(*first)); - - std::vector points(first, last); - - // Creates a vector {0, 1, ..., N-1} - std::vector indices(boost::counting_iterator(0), - boost::counting_iterator(points.size())); - - // Sort indices considering CGAL spatial sort - typedef CGAL::Spatial_sort_traits_adapter_d Search_traits_d; - spatial_sort(indices.begin(), indices.end(), Search_traits_d(&(points[0]))); - - typename Delaunay_triangulation::Full_cell_handle hint; - for (auto index : indices) { - typename Delaunay_triangulation::Vertex_handle pos = triangulation_->insert(points[index], hint); - // Save index value as data to retrieve it after insertion - pos->data() = index; - hint = pos->full_cell(); - } - init(max_alpha_square); - } - } - - /** \brief Initialize the Alpha_complex from the Delaunay triangulation. - * - * @param[in] max_alpha_square maximum for alpha square value. - * - * @warning Delaunay triangulation must be already constructed with at least one vertex and dimension must be more - * than 0. - * - * Initialization can be launched once. - */ - void init(Filtration_value max_alpha_square) { - if (triangulation_ == nullptr) { - std::cerr << "Alpha_complex init - Cannot init from a NULL triangulation\n"; - return; // ----- >> - } - if (triangulation_->number_of_vertices() < 1) { - std::cerr << "Alpha_complex init - Cannot init from a triangulation without vertices\n"; - return; // ----- >> - } - if (triangulation_->maximal_dimension() < 1) { - std::cerr << "Alpha_complex init - Cannot init from a zero-dimension triangulation\n"; - return; // ----- >> - } - if (num_vertices() > 0) { - std::cerr << "Alpha_complex init - Cannot init twice\n"; - return; // ----- >> - } - - set_dimension(triangulation_->maximal_dimension()); - - // -------------------------------------------------------------------------------------------- - // double map to retrieve simplex tree vertex handles from CGAL vertex iterator and vice versa - // Loop on triangulation vertices list - for (CGAL_vertex_iterator vit = triangulation_->vertices_begin(); vit != triangulation_->vertices_end(); ++vit) { - if (!triangulation_->is_infinite(*vit)) { -#ifdef DEBUG_TRACES - std::cout << "Vertex insertion - " << vit->data() << " -> " << vit->point() << std::endl; -#endif // DEBUG_TRACES - vertex_handle_to_iterator_.emplace(vit->data(), vit); - } - } - // -------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------- - // Simplex_tree construction from loop on triangulation finite full cells list - for (auto cit = triangulation_->finite_full_cells_begin(); cit != triangulation_->finite_full_cells_end(); ++cit) { - Vector_vertex vertexVector; -#ifdef DEBUG_TRACES - std::cout << "Simplex_tree insertion "; -#endif // DEBUG_TRACES - for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) { - if (*vit != nullptr) { -#ifdef DEBUG_TRACES - std::cout << " " << (*vit)->data(); -#endif // DEBUG_TRACES - // Vector of vertex construction for simplex_tree structure - vertexVector.push_back((*vit)->data()); - } - } -#ifdef DEBUG_TRACES - std::cout << std::endl; -#endif // DEBUG_TRACES - // Insert each simplex and its subfaces in the simplex tree - filtration is NaN - insert_simplex_and_subfaces(vertexVector, std::numeric_limits::quiet_NaN()); - } - // -------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------- - // Will be re-used many times - Vector_of_CGAL_points pointVector; - // ### For i : d -> 0 - for (int decr_dim = dimension(); decr_dim >= 0; decr_dim--) { - // ### Foreach Sigma of dim i - for (auto f_simplex : skeleton_simplex_range(decr_dim)) { - int f_simplex_dim = dimension(f_simplex); - if (decr_dim == f_simplex_dim) { - pointVector.clear(); -#ifdef DEBUG_TRACES - std::cout << "Sigma of dim " << decr_dim << " is"; -#endif // DEBUG_TRACES - for (auto vertex : simplex_vertex_range(f_simplex)) { - pointVector.push_back(get_point(vertex)); -#ifdef DEBUG_TRACES - std::cout << " " << vertex; -#endif // DEBUG_TRACES - } -#ifdef DEBUG_TRACES - std::cout << std::endl; -#endif // DEBUG_TRACES - // ### If filt(Sigma) is NaN : filt(Sigma) = alpha(Sigma) - if (isnan(filtration(f_simplex))) { - Filtration_value alpha_complex_filtration = 0.0; - // No need to compute squared_radius on a single point - alpha is 0.0 - if (f_simplex_dim > 0) { - // squared_radius function initialization - Squared_Radius squared_radius = kernel_.compute_squared_radius_d_object(); - - alpha_complex_filtration = squared_radius(pointVector.begin(), pointVector.end()); - } - assign_filtration(f_simplex, alpha_complex_filtration); -#ifdef DEBUG_TRACES - std::cout << "filt(Sigma) is NaN : filt(Sigma) =" << filtration(f_simplex) << std::endl; -#endif // DEBUG_TRACES - } - propagate_alpha_filtration(f_simplex, decr_dim); - } - } - } - // -------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------- - // As Alpha value is an approximation, we have to make filtration non decreasing while increasing the dimension - bool modified_filt = make_filtration_non_decreasing(); - // Remove all simplices that have a filtration value greater than max_alpha_square - // Remark: prune_above_filtration does not require initialize_filtration to be done before. - modified_filt |= prune_above_filtration(max_alpha_square); - if (modified_filt) { - initialize_filtration(); - } - // -------------------------------------------------------------------------------------------- - } - - template - void propagate_alpha_filtration(Simplex_handle f_simplex, int decr_dim) { - // ### Foreach Tau face of Sigma - for (auto f_boundary : boundary_simplex_range(f_simplex)) { -#ifdef DEBUG_TRACES - std::cout << " | --------------------------------------------------\n"; - std::cout << " | Tau "; - for (auto vertex : simplex_vertex_range(f_boundary)) { - std::cout << vertex << " "; - } - std::cout << "is a face of Sigma\n"; - std::cout << " | isnan(filtration(Tau)=" << isnan(filtration(f_boundary)) << std::endl; -#endif // DEBUG_TRACES - // ### If filt(Tau) is not NaN - if (!isnan(filtration(f_boundary))) { - // ### filt(Tau) = fmin(filt(Tau), filt(Sigma)) - Filtration_value alpha_complex_filtration = fmin(filtration(f_boundary), filtration(f_simplex)); - assign_filtration(f_boundary, alpha_complex_filtration); -#ifdef DEBUG_TRACES - std::cout << " | filt(Tau) = fmin(filt(Tau), filt(Sigma)) = " << filtration(f_boundary) << std::endl; -#endif // DEBUG_TRACES - // ### Else - } else { - // No need to compute is_gabriel for dimension <= 2 - // i.e. : Sigma = (3,1) => Tau = 1 - if (decr_dim > 1) { - // insert the Tau points in a vector for is_gabriel function - Vector_of_CGAL_points pointVector; -#ifdef DEBUG_TRACES - Vertex_handle vertexForGabriel = Vertex_handle(); -#endif // DEBUG_TRACES - for (auto vertex : simplex_vertex_range(f_boundary)) { - pointVector.push_back(get_point(vertex)); - } - // Retrieve the Sigma point that is not part of Tau - parameter for is_gabriel function - Point_d point_for_gabriel; - for (auto vertex : simplex_vertex_range(f_simplex)) { - point_for_gabriel = get_point(vertex); - if (std::find(pointVector.begin(), pointVector.end(), point_for_gabriel) == pointVector.end()) { -#ifdef DEBUG_TRACES - // vertex is not found in Tau - vertexForGabriel = vertex; -#endif // DEBUG_TRACES - // No need to continue loop - break; - } - } - // is_gabriel function initialization - Is_Gabriel is_gabriel = kernel_.side_of_bounded_sphere_d_object(); - bool is_gab = is_gabriel(pointVector.begin(), pointVector.end(), point_for_gabriel) - != CGAL::ON_BOUNDED_SIDE; -#ifdef DEBUG_TRACES - std::cout << " | Tau is_gabriel(Sigma)=" << is_gab << " - vertexForGabriel=" << vertexForGabriel << std::endl; -#endif // DEBUG_TRACES - // ### If Tau is not Gabriel of Sigma - if (false == is_gab) { - // ### filt(Tau) = filt(Sigma) - Filtration_value alpha_complex_filtration = filtration(f_simplex); - assign_filtration(f_boundary, alpha_complex_filtration); -#ifdef DEBUG_TRACES - std::cout << " | filt(Tau) = filt(Sigma) = " << filtration(f_boundary) << std::endl; -#endif // DEBUG_TRACES - } - } - } - } - } -}; - -} // namespace alphacomplex - -} // namespace Gudhi - -#endif // ALPHA_COMPLEX_H_ diff --git a/include/gudhi/Bottleneck.h b/include/gudhi/Bottleneck.h new file mode 100644 index 00000000..b90a0ee0 --- /dev/null +++ b/include/gudhi/Bottleneck.h @@ -0,0 +1,115 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author: Francois Godi + * + * Copyright (C) 2015 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BOTTLENECK_H_ +#define BOTTLENECK_H_ + +#include + +#include +#include // for max +#include // for numeric_limits + +#include + +namespace Gudhi { + +namespace persistence_diagram { + +double bottleneck_distance_approx(Persistence_graph& g, double e) { + double b_lower_bound = 0.; + double b_upper_bound = g.diameter_bound(); + const double alpha = std::pow(g.size(), 1. / 5.); + Graph_matching m(g); + Graph_matching biggest_unperfect(g); + while (b_upper_bound - b_lower_bound > 2 * e) { + double step = b_lower_bound + (b_upper_bound - b_lower_bound) / alpha; + if (step <= b_lower_bound || step >= b_upper_bound) // Avoid precision problem + break; + m.set_r(step); + while (m.multi_augment()) {}; // compute a maximum matching (in the graph corresponding to the current r) + if (m.perfect()) { + m = biggest_unperfect; + b_upper_bound = step; + } else { + biggest_unperfect = m; + b_lower_bound = step; + } + } + return (b_lower_bound + b_upper_bound) / 2.; +} + +double bottleneck_distance_exact(Persistence_graph& g) { + std::vector sd = g.sorted_distances(); + long lower_bound_i = 0; + long upper_bound_i = sd.size() - 1; + const double alpha = std::pow(g.size(), 1. / 5.); + Graph_matching m(g); + Graph_matching biggest_unperfect(g); + while (lower_bound_i != upper_bound_i) { + long step = lower_bound_i + static_cast ((upper_bound_i - lower_bound_i - 1) / alpha); + m.set_r(sd.at(step)); + while (m.multi_augment()) {}; // compute a maximum matching (in the graph corresponding to the current r) + if (m.perfect()) { + m = biggest_unperfect; + upper_bound_i = step; + } else { + biggest_unperfect = m; + lower_bound_i = step + 1; + } + } + return sd.at(lower_bound_i); +} + +/** \brief Function to compute the Bottleneck distance between two persistence diagrams. + * + * \tparam Persistence_diagram1,Persistence_diagram2 + * models of the concept `PersistenceDiagram`. + * \param[in] e + * \parblock + * If `e` is 0, this uses an expensive algorithm to compute the exact distance. + * + * If `e` is not 0, it asks for an additive `e`-approximation, and currently + * also allows a small multiplicative error (the last 2 or 3 bits of the + * mantissa may be wrong). This version of the algorithm takes advantage of the + * limited precision of `double` and is usually a lot faster to compute, + * whatever the value of `e`. + * + * Thus, by default, `e` is the smallest positive double. + * \endparblock + * + * \ingroup bottleneck_distance + */ +template +double bottleneck_distance(const Persistence_diagram1 &diag1, const Persistence_diagram2 &diag2, + double e = std::numeric_limits::min()) { + Persistence_graph g(diag1, diag2, e); + if (g.bottleneck_alive() == std::numeric_limits::infinity()) + return std::numeric_limits::infinity(); + return std::max(g.bottleneck_alive(), e == 0. ? bottleneck_distance_exact(g) : bottleneck_distance_approx(g, e)); +} + +} // namespace persistence_diagram + +} // namespace Gudhi + +#endif // BOTTLENECK_H_ diff --git a/include/gudhi/Clock.h b/include/gudhi/Clock.h index 04c6ffb9..77f196ca 100644 --- a/include/gudhi/Clock.h +++ b/include/gudhi/Clock.h @@ -27,47 +27,55 @@ #include +namespace Gudhi { + class Clock { public: - Clock() : end_called(false) { - startTime = boost::posix_time::microsec_clock::local_time(); - } - - Clock(const std::string& msg_) { - end_called = false; - begin(); - msg = msg_; - } + // Construct and start the timer + Clock(const std::string& msg_ = std::string()) + : startTime(boost::posix_time::microsec_clock::local_time()), + end_called(false), + msg(msg_) { } + // Restart the timer void begin() const { end_called = false; startTime = boost::posix_time::microsec_clock::local_time(); } + // Stop the timer void end() const { end_called = true; endTime = boost::posix_time::microsec_clock::local_time(); } + std::string message() const { + return msg; + } + + // Print current value to std::cout void print() const { std::cout << *this << std::endl; } friend std::ostream& operator<<(std::ostream& stream, const Clock& clock) { - if (!clock.end_called) - clock.end(); + if (!clock.msg.empty()) + stream << clock.msg << ": "; - if (!clock.end_called) { - stream << "end not called"; - } else { - stream << clock.msg << ":" << clock.num_seconds() << "s"; - } + stream << clock.num_seconds() << "s"; return stream; } + // Get the number of seconds between the timer start and: + // - the last call of end() if it was called + // - or now otherwise. In this case, the timer is not stopped. double num_seconds() const { - if (!end_called) return -1; - return (endTime - startTime).total_milliseconds() / 1000.; + if (!end_called) { + auto end = boost::posix_time::microsec_clock::local_time(); + return (end - startTime).total_milliseconds() / 1000.; + } else { + return (endTime - startTime).total_milliseconds() / 1000.; + } } private: @@ -76,4 +84,6 @@ class Clock { std::string msg; }; -#endif // CLOCK_H_ +} // namespace Gudhi + +#endif // CLOCK_H_ diff --git a/include/gudhi/Debug_utils.h b/include/gudhi/Debug_utils.h index 7573a9db..8ed3b7b3 100644 --- a/include/gudhi/Debug_utils.h +++ b/include/gudhi/Debug_utils.h @@ -33,8 +33,10 @@ // Could assert in release mode, but cmake sets NDEBUG (for "NO DEBUG") in this mode, means assert does nothing. #ifdef GUDHI_DEBUG #define GUDHI_CHECK(expression, excpt) if ((expression) == 0) throw excpt + #define GUDHI_CHECK_code(CODE) CODE #else #define GUDHI_CHECK(expression, excpt) (void) 0 + #define GUDHI_CHECK_code(CODE) #endif #define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)" << std::endl diff --git a/include/gudhi/Edge_contraction.h b/include/gudhi/Edge_contraction.h index 5af13c3e..61f2d945 100644 --- a/include/gudhi/Edge_contraction.h +++ b/include/gudhi/Edge_contraction.h @@ -41,7 +41,7 @@ namespace contraction { \author David Salinas -\section Introduction +\section edgecontractionintroduction Introduction The purpose of this package is to offer a user-friendly interface for edge contraction simplification of huge simplicial complexes. It uses the \ref skbl data-structure whose size remains small during simplification diff --git a/include/gudhi/Euclidean_strong_witness_complex.h b/include/gudhi/Euclidean_strong_witness_complex.h new file mode 100644 index 00000000..fb669ef8 --- /dev/null +++ b/include/gudhi/Euclidean_strong_witness_complex.h @@ -0,0 +1,104 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2015 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_ +#define EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_ + +#include +#include +#include + +#include +#include + +namespace Gudhi { + +namespace witness_complex { + +/** + * \private + * \class Euclidean_strong_witness_complex + * \brief Constructs strong witness complex for given sets of witnesses and landmarks in Euclidean space. + * \ingroup witness_complex + * + * \tparam Kernel_ requires a CGAL::Epick_d class. + */ +template< class Kernel_ > +class Euclidean_strong_witness_complex + : public Strong_witness_complex>::INS_range>> { + private: + typedef Kernel_ K; + typedef typename K::Point_d Point_d; + typedef std::vector Point_range; + typedef Gudhi::spatial_searching::Kd_tree_search Kd_tree; + typedef typename Kd_tree::INS_range Nearest_landmark_range; + typedef typename std::vector Nearest_landmark_table; + + typedef typename Nearest_landmark_range::Point_with_transformed_distance Id_distance_pair; + typedef typename Id_distance_pair::first_type Landmark_id; + typedef Landmark_id Vertex_handle; + + private: + Point_range landmarks_; + Kd_tree landmark_tree_; + using Strong_witness_complex::nearest_landmark_table_; + + public: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* @name Constructor + */ + + //@{ + + /** + * \brief Initializes member variables before constructing simplicial complex. + * \details Records landmarks from the range 'landmarks' into a + * table internally, as well as witnesses from the range 'witnesses'. + * Both ranges should have value_type Kernel_::Point_d. + */ + template< typename LandmarkRange, + typename WitnessRange > + Euclidean_strong_witness_complex(const LandmarkRange & landmarks, + const WitnessRange & witnesses) + : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks_) { + nearest_landmark_table_.reserve(boost::size(witnesses)); + for (auto w : witnesses) + nearest_landmark_table_.push_back(landmark_tree_.query_incremental_nearest_neighbors(w)); + } + + /** \brief Returns the point corresponding to the given vertex. + */ + template + Point_d get_point(Vertex_handle vertex) const { + return landmarks_[vertex]; + } + + //@} +}; + +} // namespace witness_complex + +} // namespace Gudhi + +#endif // EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_ diff --git a/include/gudhi/Euclidean_witness_complex.h b/include/gudhi/Euclidean_witness_complex.h new file mode 100644 index 00000000..6afe9a5d --- /dev/null +++ b/include/gudhi/Euclidean_witness_complex.h @@ -0,0 +1,106 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2015 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EUCLIDEAN_WITNESS_COMPLEX_H_ +#define EUCLIDEAN_WITNESS_COMPLEX_H_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace Gudhi { + +namespace witness_complex { + +/** + * \private + * \class Euclidean_witness_complex + * \brief Constructs (weak) witness complex for given sets of witnesses and landmarks in Euclidean space. + * \ingroup witness_complex + * + * \tparam Kernel_ requires a CGAL::Epick_d class. + */ +template< class Kernel_ > +class Euclidean_witness_complex + : public Witness_complex>::INS_range>> { + private: + typedef Kernel_ K; + typedef typename K::Point_d Point_d; + typedef std::vector Point_range; + typedef Gudhi::spatial_searching::Kd_tree_search Kd_tree; + typedef typename Kd_tree::INS_range Nearest_landmark_range; + typedef typename std::vector Nearest_landmark_table; + + typedef typename Nearest_landmark_range::Point_with_transformed_distance Id_distance_pair; + typedef typename Id_distance_pair::first_type Landmark_id; + typedef Landmark_id Vertex_handle; + + private: + Point_range landmarks_; + Kd_tree landmark_tree_; + using Witness_complex::nearest_landmark_table_; + + public: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* @name Constructor + */ + + //@{ + + /** + * \brief Initializes member variables before constructing simplicial complex. + * \details Records landmarks from the range 'landmarks' into a + * table internally, as well as witnesses from the range 'witnesses'. + * Both ranges should have value_type Kernel_::Point_d. + */ + template< typename LandmarkRange, + typename WitnessRange > + Euclidean_witness_complex(const LandmarkRange & landmarks, + const WitnessRange & witnesses) + : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks) { + nearest_landmark_table_.reserve(boost::size(witnesses)); + for (auto w : witnesses) + nearest_landmark_table_.push_back(landmark_tree_.query_incremental_nearest_neighbors(w)); + } + + /** \brief Returns the point corresponding to the given vertex. + * @param[in] vertex Vertex handle of the point to retrieve. + */ + Point_d get_point(Vertex_handle vertex) const { + return landmarks_[vertex]; + } + + //@} +}; + +} // namespace witness_complex + +} // namespace Gudhi + +#endif // EUCLIDEAN_WITNESS_COMPLEX_H_ diff --git a/include/gudhi/Graph_matching.h b/include/gudhi/Graph_matching.h new file mode 100644 index 00000000..f51e22e9 --- /dev/null +++ b/include/gudhi/Graph_matching.h @@ -0,0 +1,174 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author: Francois Godi + * + * Copyright (C) 2015 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GRAPH_MATCHING_H_ +#define GRAPH_MATCHING_H_ + +#include + +#include +#include +#include + +namespace Gudhi { + +namespace persistence_diagram { + +/** \internal \brief Structure representing a graph matching. The graph is a Persistence_diagrams_graph. + * + * \ingroup bottleneck_distance + */ +class Graph_matching { + public: + /** \internal \brief Constructor constructing an empty matching. */ + explicit Graph_matching(Persistence_graph &g); + /** \internal \brief Is the matching perfect ? */ + bool perfect() const; + /** \internal \brief Augments the matching with a maximal set of edge-disjoint shortest augmenting paths. */ + bool multi_augment(); + /** \internal \brief Sets the maximum length of the edges allowed to be added in the matching, 0 initially. */ + void set_r(double r); + + private: + Persistence_graph* gp; + double r; + /** \internal \brief Given a point from V, provides its matched point in U, null_point_index() if there isn't. */ + std::vector v_to_u; + /** \internal \brief All the unmatched points in U. */ + std::unordered_set unmatched_in_u; + + /** \internal \brief Provides a Layered_neighbors_finder dividing the graph in layers. Basically a BFS. */ + Layered_neighbors_finder layering() const; + /** \internal \brief Augments the matching with a simple path no longer than max_depth. Basically a DFS. */ + bool augment(Layered_neighbors_finder & layered_nf, int u_start_index, int max_depth); + /** \internal \brief Update the matching with the simple augmenting path given as parameter. */ + void update(std::vector & path); +}; + +inline Graph_matching::Graph_matching(Persistence_graph& g) + : gp(&g), r(0.), v_to_u(g.size(), null_point_index()), unmatched_in_u(g.size()) { + for (int u_point_index = 0; u_point_index < g.size(); ++u_point_index) + unmatched_in_u.insert(u_point_index); +} + +inline bool Graph_matching::perfect() const { + return unmatched_in_u.empty(); +} + +inline bool Graph_matching::multi_augment() { + if (perfect()) + return false; + Layered_neighbors_finder layered_nf(layering()); + int max_depth = layered_nf.vlayers_number()*2 - 1; + double rn = sqrt(gp->size()); + // verification of a necessary criterion in order to shortcut if possible + if (max_depth < 0 || (unmatched_in_u.size() > rn && max_depth >= rn)) + return false; + bool successful = false; + std::vector tries(unmatched_in_u.cbegin(), unmatched_in_u.cend()); + for (auto it = tries.cbegin(); it != tries.cend(); it++) + // 'augment' has side-effects which have to be always executed, don't change order + successful = augment(layered_nf, *it, max_depth) || successful; + return successful; +} + +inline void Graph_matching::set_r(double r) { + this->r = r; +} + +inline bool Graph_matching::augment(Layered_neighbors_finder & layered_nf, int u_start_index, int max_depth) { + // V vertices have at most one successor, thus when we backtrack from U we can directly pop_back 2 vertices. + std::vector path; + path.emplace_back(u_start_index); + do { + if (static_cast (path.size()) > max_depth) { + path.pop_back(); + path.pop_back(); + } + if (path.empty()) + return false; + path.emplace_back(layered_nf.pull_near(path.back(), static_cast (path.size()) / 2)); + while (path.back() == null_point_index()) { + path.pop_back(); + path.pop_back(); + if (path.empty()) + return false; + path.pop_back(); + path.emplace_back(layered_nf.pull_near(path.back(), path.size() / 2)); + } + path.emplace_back(v_to_u.at(path.back())); + } while (path.back() != null_point_index()); + // if v_to_u.at(path.back()) has no successor, path.back() is an exposed vertex + path.pop_back(); + update(path); + return true; +} + +inline Layered_neighbors_finder Graph_matching::layering() const { + std::vector u_vertices(unmatched_in_u.cbegin(), unmatched_in_u.cend()); + std::vector v_vertices; + Neighbors_finder nf(*gp, r); + for (int v_point_index = 0; v_point_index < gp->size(); ++v_point_index) + nf.add(v_point_index); + Layered_neighbors_finder layered_nf(*gp, r); + for (int layer = 0; !u_vertices.empty(); layer++) { + // one layer is one step in the BFS + for (auto it1 = u_vertices.cbegin(); it1 != u_vertices.cend(); ++it1) { + std::vector u_succ(nf.pull_all_near(*it1)); + for (auto it2 = u_succ.begin(); it2 != u_succ.end(); ++it2) { + layered_nf.add(*it2, layer); + v_vertices.emplace_back(*it2); + } + } + // When the above for finishes, we have progress of one half-step (from U to V) in the BFS + u_vertices.clear(); + bool end = false; + for (auto it = v_vertices.cbegin(); it != v_vertices.cend(); it++) + if (v_to_u.at(*it) == null_point_index()) + // we stop when a nearest exposed V vertex (from U exposed vertices) has been found + end = true; + else + u_vertices.emplace_back(v_to_u.at(*it)); + // When the above for finishes, we have progress of one half-step (from V to U) in the BFS + if (end) + return layered_nf; + v_vertices.clear(); + } + return layered_nf; +} + +inline void Graph_matching::update(std::vector& path) { + // Must return 1. + unmatched_in_u.erase(path.front()); + for (auto it = path.cbegin(); it != path.cend(); ++it) { + // Be careful, the iterator is incremented twice each time + int tmp = *it; + v_to_u[*(++it)] = tmp; + } +} + + +} // namespace persistence_diagram + +} // namespace Gudhi + +#endif // GRAPH_MATCHING_H_ diff --git a/include/gudhi/Internal_point.h b/include/gudhi/Internal_point.h new file mode 100644 index 00000000..0b2d26fe --- /dev/null +++ b/include/gudhi/Internal_point.h @@ -0,0 +1,91 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author: Francois Godi + * + * Copyright (C) 2015 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERNAL_POINT_H_ +#define INTERNAL_POINT_H_ + +namespace Gudhi { + +namespace persistence_diagram { + +/** \internal \brief Returns the used index for encoding none of the points */ +int null_point_index(); + +/** \internal \typedef \brief Internal_point is the internal points representation, indexes used outside. */ +struct Internal_point { + double vec[2]; + int point_index; + + Internal_point() { } + + Internal_point(double x, double y, int p_i) { + vec[0] = x; + vec[1] = y; + point_index = p_i; + } + + double x() const { + return vec[ 0 ]; + } + + double y() const { + return vec[ 1 ]; + } + + double& x() { + return vec[ 0 ]; + } + + double& y() { + return vec[ 1 ]; + } + + bool operator==(const Internal_point& p) const { + return point_index == p.point_index; + } + + bool operator!=(const Internal_point& p) const { + return !(*this == p); + } +}; + +inline int null_point_index() { + return -1; +} + +struct Construct_coord_iterator { + typedef const double* result_type; + + const double* operator()(const Internal_point& p) const { + return p.vec; + } + + const double* operator()(const Internal_point& p, int) const { + return p.vec + 2; + } +}; + +} // namespace persistence_diagram + +} // namespace Gudhi + +#endif // INTERNAL_POINT_H_ diff --git a/include/gudhi/Kd_tree_search.h b/include/gudhi/Kd_tree_search.h new file mode 100644 index 00000000..6728d56e --- /dev/null +++ b/include/gudhi/Kd_tree_search.h @@ -0,0 +1,264 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KD_TREE_SEARCH_H_ +#define KD_TREE_SEARCH_H_ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace Gudhi { +namespace spatial_searching { + + + /** + * \class Kd_tree_search Kd_tree_search.h gudhi/Kd_tree_search.h + * \brief Spatial tree data structure to perform (approximate) nearest and farthest neighbor search. + * + * \ingroup spatial_searching + * + * \details + * The class Kd_tree_search is a tree-based data structure, based on + * CGAL dD spatial searching data structures. + * It provides a simplified API to perform (approximate) nearest and farthest neighbor searches. Contrary to CGAL default behavior, the tree + * does not store the points themselves, but stores indices. + * + * There are two types of queries: the k-nearest or k-farthest neighbor query, where k is fixed and the k nearest + * or farthest points are computed right away, + * and the incremental nearest or farthest neighbor query, where no number of neighbors is provided during the call, as the + * neighbors will be computed incrementally when the iterator on the range is incremented. + * + * \tparam Search_traits must be a model of the SearchTraits + * concept, such as the CGAL::Epick_d class, which + * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't. + * \tparam Point_range is the type of the range that provides the points. + * It must be a range whose iterator type is a `RandomAccessIterator`. + */ +template +class Kd_tree_search { + typedef boost::iterator_property_map< + typename Point_range::const_iterator, + CGAL::Identity_property_map > Point_property_map; + + public: + /// The Traits. + typedef Search_traits Traits; + /// Number type used for distances. + typedef typename Traits::FT FT; + /// The point type. + typedef typename Point_range::value_type Point; + + typedef CGAL::Search_traits< + FT, Point, + typename Traits::Cartesian_const_iterator_d, + typename Traits::Construct_cartesian_const_iterator_d> Traits_base; + + typedef CGAL::Search_traits_adapter< + std::ptrdiff_t, + Point_property_map, + Traits_base> STraits; + + typedef CGAL::Orthogonal_k_neighbor_search K_neighbor_search; + typedef typename K_neighbor_search::Tree Tree; + typedef typename K_neighbor_search::Distance Distance; + /// \brief The range returned by a k-nearest or k-farthest neighbor search. + /// Its value type is `std::pair` where `first` is the index + /// of a point P and `second` is the squared distance between P and the query point. + typedef K_neighbor_search KNS_range; + + typedef CGAL::Orthogonal_incremental_neighbor_search< + STraits, Distance, CGAL::Sliding_midpoint, Tree> + Incremental_neighbor_search; + /// \brief The range returned by an incremental nearest or farthest neighbor search. + /// Its value type is `std::pair` where `first` is the index + /// of a point P and `second` is the squared distance between P and the query point. + typedef Incremental_neighbor_search INS_range; + + /// \brief Constructor + /// @param[in] points Const reference to the point range. This range + /// is not copied, so it should not be destroyed or modified afterwards. + Kd_tree_search(Point_range const& points) + : m_points(points), + m_tree(boost::counting_iterator(0), + boost::counting_iterator(points.size()), + typename Tree::Splitter(), + STraits(std::begin(points))) { + // Build the tree now (we don't want to wait for the first query) + m_tree.build(); + } + + /// \brief Constructor + /// @param[in] points Const reference to the point range. This range + /// is not copied, so it should not be destroyed or modified afterwards. + /// @param[in] only_these_points Specifies the indices of the points that + /// should be actually inserted into the tree. The other points are ignored. + template + Kd_tree_search( + Point_range const& points, + Point_indices_range const& only_these_points) + : m_points(points), + m_tree( + only_these_points.begin(), only_these_points.end(), + typename Tree::Splitter(), + STraits(std::begin(points))) { + // Build the tree now (we don't want to wait for the first query) + m_tree.build(); + } + + /// \brief Constructor + /// @param[in] points Const reference to the point range. This range + /// is not copied, so it should not be destroyed or modified afterwards. + /// @param[in] begin_idx, past_the_end_idx Define the subset of the points that + /// should be actually inserted into the tree. The other points are ignored. + Kd_tree_search( + Point_range const& points, + std::size_t begin_idx, std::size_t past_the_end_idx) + : m_points(points), + m_tree( + boost::counting_iterator(begin_idx), + boost::counting_iterator(past_the_end_idx), + typename Tree::Splitter(), + STraits(std::begin(points))) { + // Build the tree now (we don't want to wait for the first query) + m_tree.build(); + } + + // Be careful, this function invalidates the tree, + // which will be recomputed at the next query + void insert(std::ptrdiff_t point_idx) { + m_tree.insert(point_idx); + } + + /// \brief Search for the k-nearest neighbors from a query point. + /// @param[in] p The query point. + /// @param[in] k Number of nearest points to search. + /// @param[in] sorted Indicates if the computed sequence of k-nearest neighbors needs to be sorted. + /// @param[in] eps Approximation factor. + /// @return A range containing the k-nearest neighbors. + KNS_range query_k_nearest_neighbors(const + Point &p, + unsigned int k, + bool sorted = true, + FT eps = FT(0)) const { + // Initialize the search structure, and search all N points + // Note that we need to pass the Distance explicitly since it needs to + // know the property map + K_neighbor_search search( + m_tree, + p, + k, + eps, + true, + CGAL::Distance_adapter >( + std::begin(m_points)), sorted); + + return search; + } + + /// \brief Search incrementally for the nearest neighbors from a query point. + /// @param[in] p The query point. + /// @param[in] eps Approximation factor. + /// @return A range containing the neighbors sorted by their distance to p. + /// All the neighbors are not computed by this function, but they will be + /// computed incrementally when the iterator on the range is incremented. + INS_range query_incremental_nearest_neighbors(const Point &p, FT eps = FT(0)) const { + // Initialize the search structure, and search all N points + // Note that we need to pass the Distance explicitly since it needs to + // know the property map + Incremental_neighbor_search search( + m_tree, + p, + eps, + true, + CGAL::Distance_adapter >( + std::begin(m_points)) ); + + return search; + } + + /// \brief Search for the k-farthest points from a query point. + /// @param[in] p The query point. + /// @param[in] k Number of farthest points to search. + /// @param[in] sorted Indicates if the computed sequence of k-farthest neighbors needs to be sorted. + /// @param[in] eps Approximation factor. + /// @return A range containing the k-farthest neighbors. + KNS_range query_k_farthest_neighbors(const + Point &p, + unsigned int k, + bool sorted = true, + FT eps = FT(0)) const { + // Initialize the search structure, and search all N points + // Note that we need to pass the Distance explicitly since it needs to + // know the property map + K_neighbor_search search( + m_tree, + p, + k, + eps, + false, + CGAL::Distance_adapter >( + std::begin(m_points)), sorted); + + return search; + } + + /// \brief Search incrementally for the farthest neighbors from a query point. + /// @param[in] p The query point. + /// @param[in] eps Approximation factor. + /// @return A range containing the neighbors sorted by their distance to p. + /// All the neighbors are not computed by this function, but they will be + /// computed incrementally when the iterator on the range is incremented. + INS_range query_incremental_farthest_neighbors(const Point &p, FT eps = FT(0)) const { + // Initialize the search structure, and search all N points + // Note that we need to pass the Distance explicitly since it needs to + // know the property map + Incremental_neighbor_search search( + m_tree, + p, + eps, + false, + CGAL::Distance_adapter >( + std::begin(m_points)) ); + + return search; + } + + private: + Point_range const& m_points; + Tree m_tree; +}; + +} // namespace spatial_searching +} // namespace Gudhi + +#endif // KD_TREE_SEARCH_H_ diff --git a/include/gudhi/Landmark_choice_by_furthest_point.h b/include/gudhi/Landmark_choice_by_furthest_point.h deleted file mode 100644 index df93155b..00000000 --- a/include/gudhi/Landmark_choice_by_furthest_point.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * - * Author(s): Siargey Kachanovich - * - * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LANDMARK_CHOICE_BY_FURTHEST_POINT_H_ -#define LANDMARK_CHOICE_BY_FURTHEST_POINT_H_ - -#include - -#include // for numeric_limits<> -#include -#include // for sort -#include - -namespace Gudhi { - -namespace witness_complex { - - typedef std::vector typeVectorVertex; - - /** - * \ingroup witness_complex - * \brief Landmark choice strategy by iteratively adding the furthest witness from the - * current landmark set as the new landmark. - * \details It chooses nbL landmarks from a random access range `points` and - * writes {witness}*{closest landmarks} matrix in `knn`. - * - * The type KNearestNeighbors can be seen as - * Witness_range>, where - * Witness_range and Closest_landmark_range are random access ranges - * - */ - - template - void landmark_choice_by_furthest_point(Point_random_access_range const &points, - int nbL, - KNearestNeighbours &knn) { - int nb_points = boost::size(points); - assert(nb_points >= nbL); - // distance matrix witness x landmarks - std::vector> wit_land_dist(nb_points, std::vector()); - // landmark list - typeVectorVertex chosen_landmarks; - - knn = KNearestNeighbours(nb_points, std::vector()); - int current_number_of_landmarks = 0; // counter for landmarks - double curr_max_dist = 0; // used for defining the furhest point from L - const double infty = std::numeric_limits::infinity(); // infinity (see next entry) - std::vector< double > dist_to_L(nb_points, infty); // vector of current distances to L from points - - // TODO(SK) Consider using rand_r(...) instead of rand(...) for improved thread safety - // or better yet std::uniform_int_distribution - int rand_int = rand() % nb_points; - int curr_max_w = rand_int; // For testing purposes a pseudo-random number is used here - - for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++) { - // curr_max_w at this point is the next landmark - chosen_landmarks.push_back(curr_max_w); - unsigned i = 0; - for (auto& p : points) { - double curr_dist = euclidean_distance(p, *(std::begin(points) + chosen_landmarks[current_number_of_landmarks])); - wit_land_dist[i].push_back(curr_dist); - knn[i].push_back(current_number_of_landmarks); - if (curr_dist < dist_to_L[i]) - dist_to_L[i] = curr_dist; - ++i; - } - curr_max_dist = 0; - for (i = 0; i < dist_to_L.size(); i++) - if (dist_to_L[i] > curr_max_dist) { - curr_max_dist = dist_to_L[i]; - curr_max_w = i; - } - } - for (int i = 0; i < nb_points; ++i) - std::sort(std::begin(knn[i]), - std::end(knn[i]), - [&wit_land_dist, i](int a, int b) { - return wit_land_dist[i][a] < wit_land_dist[i][b]; }); - } - -} // namespace witness_complex - -} // namespace Gudhi - -#endif // LANDMARK_CHOICE_BY_FURTHEST_POINT_H_ diff --git a/include/gudhi/Landmark_choice_by_random_point.h b/include/gudhi/Landmark_choice_by_random_point.h deleted file mode 100644 index ebf6aad1..00000000 --- a/include/gudhi/Landmark_choice_by_random_point.h +++ /dev/null @@ -1,96 +0,0 @@ -/* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * - * Author(s): Siargey Kachanovich - * - * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LANDMARK_CHOICE_BY_RANDOM_POINT_H_ -#define LANDMARK_CHOICE_BY_RANDOM_POINT_H_ - -#include - -#include // for priority_queue<> -#include // for pair<> -#include -#include -#include - -namespace Gudhi { - -namespace witness_complex { - - /** - * \ingroup witness_complex - * \brief Landmark choice strategy by taking random vertices for landmarks. - * \details It chooses nbL distinct landmarks from a random access range `points` - * and outputs a matrix {witness}*{closest landmarks} in knn. - * - * The type KNearestNeighbors can be seen as - * Witness_range>, where - * Witness_range and Closest_landmark_range are random access ranges and - * Vertex_handle is the label type of a vertex in a simplicial complex. - * Closest_landmark_range needs to have push_back operation. - */ - - template - void landmark_choice_by_random_point(Point_random_access_range const &points, - int nbL, - KNearestNeighbours &knn) { - int nbP = boost::size(points); - assert(nbP >= nbL); - std::set landmarks; - int current_number_of_landmarks = 0; // counter for landmarks - - // TODO(SK) Consider using rand_r(...) instead of rand(...) for improved thread safety - int chosen_landmark = rand() % nbP; - for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++) { - while (landmarks.find(chosen_landmark) != landmarks.end()) - chosen_landmark = rand() % nbP; - landmarks.insert(chosen_landmark); - } - - int dim = boost::size(*std::begin(points)); - typedef std::pair dist_i; - typedef bool (*comp)(dist_i, dist_i); - knn = KNearestNeighbours(nbP); - for (int points_i = 0; points_i < nbP; points_i++) { - std::priority_queue, comp> l_heap([](dist_i j1, dist_i j2) { - return j1.first > j2.first; - }); - std::set::iterator landmarks_it; - int landmarks_i = 0; - for (landmarks_it = landmarks.begin(), landmarks_i = 0; landmarks_it != landmarks.end(); - ++landmarks_it, landmarks_i++) { - dist_i dist = std::make_pair(euclidean_distance(points[points_i], points[*landmarks_it]), landmarks_i); - l_heap.push(dist); - } - for (int i = 0; i < dim + 1; i++) { - dist_i dist = l_heap.top(); - knn[points_i].push_back(dist.second); - l_heap.pop(); - } - } - } - -} // namespace witness_complex - -} // namespace Gudhi - -#endif // LANDMARK_CHOICE_BY_RANDOM_POINT_H_ diff --git a/include/gudhi/Neighbors_finder.h b/include/gudhi/Neighbors_finder.h new file mode 100644 index 00000000..bdc47578 --- /dev/null +++ b/include/gudhi/Neighbors_finder.h @@ -0,0 +1,192 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author: Francois Godi + * + * Copyright (C) 2015 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NEIGHBORS_FINDER_H_ +#define NEIGHBORS_FINDER_H_ + +// Inclusion order is important for CGAL patch +#include +#include + +#include +#include + +#include +#include + +namespace Gudhi { + +namespace persistence_diagram { + +/** \internal \brief Variant of CGAL::Fuzzy_iso_box to ensure that the box ic closed. It isn't clear how necessary that is. + */ +struct Square_query { + typedef CGAL::Dimension_tag<2> D; + typedef Internal_point Point_d; + typedef double FT; + bool contains(Point_d p) const { + return std::abs(p.x()-c.x())<=size && std::abs(p.y()-c.y())<=size; + } + bool inner_range_intersects(CGAL::Kd_tree_rectangle const&r) const { + return + r.max_coord(0) >= c.x() - size && + r.min_coord(0) <= c.x() + size && + r.max_coord(1) >= c.y() - size && + r.min_coord(1) <= c.y() + size; + } + bool outer_range_contains(CGAL::Kd_tree_rectangle const&r) const { + return + r.min_coord(0) >= c.x() - size && + r.max_coord(0) <= c.x() + size && + r.min_coord(1) >= c.y() - size && + r.max_coord(1) <= c.y() + size; + } + Point_d c; + FT size; +}; + +/** \internal \brief data structure used to find any point (including projections) in V near to a query point from U + * (which can be a projection). + * + * V points have to be added manually using their index and before the first pull. A neighbor pulled is automatically + * removed. + * + * \ingroup bottleneck_distance + */ +class Neighbors_finder { + typedef CGAL::Dimension_tag<2> D; + typedef CGAL::Search_traits Traits; + typedef CGAL::Kd_tree Kd_tree; + + public: + /** \internal \brief Constructor taking the near distance definition as parameter. */ + Neighbors_finder(const Persistence_graph& g, double r); + /** \internal \brief A point added will be possibly pulled. */ + void add(int v_point_index); + /** \internal \brief Returns and remove a V point near to the U point given as parameter, null_point_index() if + * there isn't such a point. */ + int pull_near(int u_point_index); + /** \internal \brief Returns and remove all the V points near to the U point given as parameter. */ + std::vector pull_all_near(int u_point_index); + + private: + const Persistence_graph& g; + const double r; + Kd_tree kd_t; + std::unordered_set projections_f; +}; + +/** \internal \brief data structure used to find any point (including projections) in V near to a query point from U + * (which can be a projection) in a layered graph layer given as parmeter. + * + * V points have to be added manually using their index and before the first pull. A neighbor pulled is automatically + * removed. + * + * \ingroup bottleneck_distance + */ +class Layered_neighbors_finder { + public: + /** \internal \brief Constructor taking the near distance definition as parameter. */ + Layered_neighbors_finder(const Persistence_graph& g, double r); + /** \internal \brief A point added will be possibly pulled. */ + void add(int v_point_index, int vlayer); + /** \internal \brief Returns and remove a V point near to the U point given as parameter, null_point_index() if + * there isn't such a point. */ + int pull_near(int u_point_index, int vlayer); + /** \internal \brief Returns the number of layers. */ + int vlayers_number() const; + + private: + const Persistence_graph& g; + const double r; + std::vector> neighbors_finder; +}; + +inline Neighbors_finder::Neighbors_finder(const Persistence_graph& g, double r) : + g(g), r(r), kd_t(), projections_f() { } + +inline void Neighbors_finder::add(int v_point_index) { + if (g.on_the_v_diagonal(v_point_index)) + projections_f.emplace(v_point_index); + else + kd_t.insert(g.get_v_point(v_point_index)); +} + +inline int Neighbors_finder::pull_near(int u_point_index) { + int tmp; + int c = g.corresponding_point_in_v(u_point_index); + if (g.on_the_u_diagonal(u_point_index) && !projections_f.empty()) { + // Any pair of projection is at distance 0 + tmp = *projections_f.cbegin(); + projections_f.erase(tmp); + } else if (projections_f.count(c) && (g.distance(u_point_index, c) <= r)) { + // Is the query point near to its projection ? + tmp = c; + projections_f.erase(tmp); + } else { + // Is the query point near to a V point in the plane ? + Internal_point u_point = g.get_u_point(u_point_index); + auto neighbor = kd_t.search_any_point(Square_query{u_point, r}); + if(!neighbor) + return null_point_index(); + tmp = neighbor->point_index; + auto point = g.get_v_point(tmp); + int idx = point.point_index; + kd_t.remove(point, [idx](Internal_point const&p){return p.point_index == idx;}); + } + return tmp; +} + +inline std::vector Neighbors_finder::pull_all_near(int u_point_index) { + std::vector all_pull; + int last_pull = pull_near(u_point_index); + while (last_pull != null_point_index()) { + all_pull.emplace_back(last_pull); + last_pull = pull_near(u_point_index); + } + return all_pull; +} + +inline Layered_neighbors_finder::Layered_neighbors_finder(const Persistence_graph& g, double r) : + g(g), r(r), neighbors_finder() { } + +inline void Layered_neighbors_finder::add(int v_point_index, int vlayer) { + for (int l = neighbors_finder.size(); l <= vlayer; l++) + neighbors_finder.emplace_back(std::unique_ptr(new Neighbors_finder(g, r))); + neighbors_finder.at(vlayer)->add(v_point_index); +} + +inline int Layered_neighbors_finder::pull_near(int u_point_index, int vlayer) { + if (static_cast (neighbors_finder.size()) <= vlayer) + return null_point_index(); + return neighbors_finder.at(vlayer)->pull_near(u_point_index); +} + +inline int Layered_neighbors_finder::vlayers_number() const { + return static_cast (neighbors_finder.size()); +} + +} // namespace persistence_diagram + +} // namespace Gudhi + +#endif // NEIGHBORS_FINDER_H_ diff --git a/include/gudhi/Null_output_iterator.h b/include/gudhi/Null_output_iterator.h new file mode 100644 index 00000000..42e6e449 --- /dev/null +++ b/include/gudhi/Null_output_iterator.h @@ -0,0 +1,48 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Marc Glisse + * + * Copyright (C) 2017 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NULL_OUTPUT_ITERATOR_H_ +#define NULL_OUTPUT_ITERATOR_H_ + +#include + +namespace Gudhi { + +/** An output iterator that ignores whatever it is given. */ +struct Null_output_iterator { + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + Null_output_iterator& operator++() {return *this;} + Null_output_iterator operator++(int) {return *this;} + struct proxy { + template + proxy& operator=(T&&){return *this;} + }; + proxy operator*()const{return {};} +}; +} // namespace Gudhi + +#endif // NULL_OUTPUT_ITERATOR_H_ diff --git a/include/gudhi/Persistence_graph.h b/include/gudhi/Persistence_graph.h new file mode 100644 index 00000000..44f4b827 --- /dev/null +++ b/include/gudhi/Persistence_graph.h @@ -0,0 +1,188 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author: Francois Godi + * + * Copyright (C) 2015 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PERSISTENCE_GRAPH_H_ +#define PERSISTENCE_GRAPH_H_ + +#include + +#ifdef GUDHI_USE_TBB +#include +#endif + +#include +#include +#include // for numeric_limits + +namespace Gudhi { + +namespace persistence_diagram { + +/** \internal \brief Structure representing an euclidean bipartite graph containing + * the points from the two persistence diagrams (including the projections). + * + * \ingroup bottleneck_distance + */ +class Persistence_graph { + public: + /** \internal \brief Constructor taking 2 PersistenceDiagrams (concept) as parameters. */ + template + Persistence_graph(const Persistence_diagram1& diag1, const Persistence_diagram2& diag2, double e); + /** \internal \brief Is the given point from U the projection of a point in V ? */ + bool on_the_u_diagonal(int u_point_index) const; + /** \internal \brief Is the given point from V the projection of a point in U ? */ + bool on_the_v_diagonal(int v_point_index) const; + /** \internal \brief Given a point from V, returns the corresponding (projection or projector) point in U. */ + int corresponding_point_in_u(int v_point_index) const; + /** \internal \brief Given a point from U, returns the corresponding (projection or projector) point in V. */ + int corresponding_point_in_v(int u_point_index) const; + /** \internal \brief Given a point from U and a point from V, returns the distance between those points. */ + double distance(int u_point_index, int v_point_index) const; + /** \internal \brief Returns size = |U| = |V|. */ + int size() const; + /** \internal \brief Is there as many infinite points (alive components) in both diagrams ? */ + double bottleneck_alive() const; + /** \internal \brief Returns the O(n^2) sorted distances between the points. */ + std::vector sorted_distances() const; + /** \internal \brief Returns an upper bound for the diameter of the convex hull of all non infinite points */ + double diameter_bound() const; + /** \internal \brief Returns the corresponding internal point */ + Internal_point get_u_point(int u_point_index) const; + /** \internal \brief Returns the corresponding internal point */ + Internal_point get_v_point(int v_point_index) const; + + private: + std::vector u; + std::vector v; + double b_alive; +}; + +template +Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1, + const Persistence_diagram2 &diag2, double e) + : u(), v(), b_alive(0.) { + std::vector u_alive; + std::vector v_alive; + for (auto it = std::begin(diag1); it != std::end(diag1); ++it) { + if (std::get<1>(*it) == std::numeric_limits::infinity()) + u_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size())); + } + for (auto it = std::begin(diag2); it != std::end(diag2); ++it) { + if (std::get<1>(*it) == std::numeric_limits::infinity()) + v_alive.push_back(std::get<0>(*it)); + else if (std::get<1>(*it) - std::get<0>(*it) > e) + v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size())); + } + if (u.size() < v.size()) + swap(u, v); + std::sort(u_alive.begin(), u_alive.end()); + std::sort(v_alive.begin(), v_alive.end()); + if (u_alive.size() != v_alive.size()) { + b_alive = std::numeric_limits::infinity(); + } else { + for (auto it_u = u_alive.cbegin(), it_v = v_alive.cbegin(); it_u != u_alive.cend(); ++it_u, ++it_v) + b_alive = std::max(b_alive, std::fabs(*it_u - *it_v)); + } +} + +inline bool Persistence_graph::on_the_u_diagonal(int u_point_index) const { + return u_point_index >= static_cast (u.size()); +} + +inline bool Persistence_graph::on_the_v_diagonal(int v_point_index) const { + return v_point_index >= static_cast (v.size()); +} + +inline int Persistence_graph::corresponding_point_in_u(int v_point_index) const { + return on_the_v_diagonal(v_point_index) ? + v_point_index - static_cast (v.size()) : v_point_index + static_cast (u.size()); +} + +inline int Persistence_graph::corresponding_point_in_v(int u_point_index) const { + return on_the_u_diagonal(u_point_index) ? + u_point_index - static_cast (u.size()) : u_point_index + static_cast (v.size()); +} + +inline double Persistence_graph::distance(int u_point_index, int v_point_index) const { + if (on_the_u_diagonal(u_point_index) && on_the_v_diagonal(v_point_index)) + return 0.; + Internal_point p_u = get_u_point(u_point_index); + Internal_point p_v = get_v_point(v_point_index); + return std::max(std::fabs(p_u.x() - p_v.x()), std::fabs(p_u.y() - p_v.y())); +} + +inline int Persistence_graph::size() const { + return static_cast (u.size() + v.size()); +} + +inline double Persistence_graph::bottleneck_alive() const { + return b_alive; +} + +inline std::vector Persistence_graph::sorted_distances() const { + std::vector distances; + distances.push_back(0.); // for empty diagrams + for (int u_point_index = 0; u_point_index < size(); ++u_point_index) { + distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index))); + for (int v_point_index = 0; v_point_index < size(); ++v_point_index) + distances.push_back(distance(u_point_index, v_point_index)); + } +#ifdef GUDHI_USE_TBB + tbb::parallel_sort(distances.begin(), distances.end()); +#else + std::sort(distances.begin(), distances.end()); +#endif + return distances; +} + +inline Internal_point Persistence_graph::get_u_point(int u_point_index) const { + if (!on_the_u_diagonal(u_point_index)) + return u.at(u_point_index); + Internal_point projector = v.at(corresponding_point_in_v(u_point_index)); + double m = (projector.x() + projector.y()) / 2.; + return Internal_point(m, m, u_point_index); +} + +inline Internal_point Persistence_graph::get_v_point(int v_point_index) const { + if (!on_the_v_diagonal(v_point_index)) + return v.at(v_point_index); + Internal_point projector = u.at(corresponding_point_in_u(v_point_index)); + double m = (projector.x() + projector.y()) / 2.; + return Internal_point(m, m, v_point_index); +} + +inline double Persistence_graph::diameter_bound() const { + double max = 0.; + for (auto it = u.cbegin(); it != u.cend(); it++) + max = std::max(max, it->y()); + for (auto it = v.cbegin(); it != v.cend(); it++) + max = std::max(max, it->y()); + return max; +} + +} // namespace persistence_diagram + +} // namespace Gudhi + +#endif // PERSISTENCE_GRAPH_H_ diff --git a/include/gudhi/Persistent_cohomology.h b/include/gudhi/Persistent_cohomology.h index b31df6a4..672fda48 100644 --- a/include/gudhi/Persistent_cohomology.h +++ b/include/gudhi/Persistent_cohomology.h @@ -110,7 +110,7 @@ class Persistent_cohomology { cell_pool_() { if (cpx_->num_simplices() > std::numeric_limits::max()) { // num_simplices must be strictly lower than the limit, because a value is reserved for null_key. - throw std::out_of_range ("The number of simplices is more than Simplex_key type numeric limit."); + throw std::out_of_range("The number of simplices is more than Simplex_key type numeric limit."); } Simplex_key idx_fil = 0; for (auto sh : cpx_->filtration_simplex_range()) { @@ -300,8 +300,7 @@ class Persistent_cohomology { // with multiplicity. We used to sum the coefficients directly in // annotations_in_boundary by using a map, we now do it later. typedef std::pair annotation_t; - // Danger: not thread-safe! - static std::vector annotations_in_boundary; + thread_local std::vector annotations_in_boundary; annotations_in_boundary.clear(); int sign = 1 - 2 * (dim_sigma % 2); // \in {-1,1} provides the sign in the // alternate sum in the boundary. @@ -604,7 +603,7 @@ class Persistent_cohomology { */ std::vector betti_numbers() const { // Init Betti numbers vector with zeros until Simplicial complex dimension - std::vector betti_numbers(cpx_->dimension(), 0); + std::vector betti_numbers(dim_max_, 0); for (auto pair : persistent_pairs_) { // Count never ended persistence intervals @@ -643,8 +642,7 @@ class Persistent_cohomology { */ std::vector persistent_betti_numbers(Filtration_value from, Filtration_value to) const { // Init Betti numbers vector with zeros until Simplicial complex dimension - std::vector betti_numbers(cpx_->dimension(), 0); - + std::vector betti_numbers(dim_max_, 0); for (auto pair : persistent_pairs_) { // Count persistence intervals that covers the given interval // null_simplex test : if the function is called with to=+infinity, we still get something useful. And it will @@ -690,6 +688,22 @@ class Persistent_cohomology { return persistent_pairs_; } + /** @brief Returns persistence intervals for a given dimension. + * @param[in] dimension Dimension to get the birth and death pairs from. + * @return A vector of persistence intervals (birth and death) on a fixed dimension. + */ + std::vector< std::pair< Filtration_value , Filtration_value > > + intervals_in_dimension(int dimension) { + std::vector< std::pair< Filtration_value , Filtration_value > > result; + // auto && pair, to avoid unnecessary copying + for (auto && pair : persistent_pairs_) { + if (cpx_->dimension(get<0>(pair)) == dimension) { + result.emplace_back(cpx_->filtration(get<0>(pair)), cpx_->filtration(get<1>(pair))); + } + } + return result; + } + private: /* * Structure representing a cocycle. diff --git a/include/gudhi/Points_3D_off_io.h b/include/gudhi/Points_3D_off_io.h index 2647f11e..b0d24998 100644 --- a/include/gudhi/Points_3D_off_io.h +++ b/include/gudhi/Points_3D_off_io.h @@ -132,12 +132,12 @@ class Points_3D_off_visitor_reader { * * @code template Point_3::Point_3(double x, double y, double z) @endcode * - * @section Example + * @section point3doffioexample Example * * This example loads points from an OFF file and builds a vector of CGAL points in dimension 3. * Then, it is asked to display the points. * - * @include common/CGAL_3D_points_off_reader.cpp + * @include common/example_CGAL_3D_points_off_reader.cpp * * When launching: * diff --git a/include/gudhi/Points_off_io.h b/include/gudhi/Points_off_io.h index 74b49386..29af8a8a 100644 --- a/include/gudhi/Points_off_io.h +++ b/include/gudhi/Points_off_io.h @@ -73,9 +73,8 @@ class Points_off_visitor_reader { * @details * Point_d must have a constructor with the following form: * - * @code template Point_d::Point_d(int d, InputIterator first, InputIterator last) @endcode + * @code template Point_d::Point_d(InputIterator first, InputIterator last) @endcode * - * where d is the point dimension. */ void point(const std::vector& point) { #ifdef DEBUG_TRACES @@ -86,7 +85,7 @@ class Points_off_visitor_reader { std::cout << std::endl; #endif // DEBUG_TRACES // Fill the point cloud - point_cloud.push_back(Point_d(point.size(), point.begin(), point.end())); + point_cloud.push_back(Point_d(point.begin(), point.end())); } // Off_reader visitor maximal_face implementation - Only points are read @@ -115,16 +114,16 @@ class Points_off_visitor_reader { * * where d is the point dimension. * - * \section Example + * \section pointoffioexample Example * - * This example loads points from an OFF file and builds a vector of CGAL points in dimension d. + * This example loads points from an OFF file and builds a vector of points (vector of double). * Then, it is asked to display the points. * - * \include common/CGAL_points_off_reader.cpp + * \include common/example_vector_double_points_off_reader.cpp * * When launching: * - * \code $> ./cgaloffreader ../../data/points/alphacomplexdoc.off + * \code $> ./vector_double_off_reader ../../data/points/alphacomplexdoc.off * \endcode * * the program output is: diff --git a/include/gudhi/Rips_complex.h b/include/gudhi/Rips_complex.h new file mode 100644 index 00000000..1e4b76a7 --- /dev/null +++ b/include/gudhi/Rips_complex.h @@ -0,0 +1,185 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clément Maria, Pawel Dlotko, Vincent Rouvreau + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef RIPS_COMPLEX_H_ +#define RIPS_COMPLEX_H_ + +#include +#include + +#include + +#include +#include +#include +#include +#include // for numeric_limits +#include // for pair<> + + +namespace Gudhi { + +namespace rips_complex { + +/** + * \class Rips_complex + * \brief Rips complex data structure. + * + * \ingroup rips_complex + * + * \details + * The data structure is a one skeleton graph, or Rips graph, containing edges when the edge length is less or equal + * to a given threshold. Edge length is computed from a user given point cloud with a given distance function, or a + * distance matrix. + * + * \tparam Filtration_value is the type used to store the filtration values of the simplicial complex. + */ +template +class Rips_complex { + public: + /** + * \brief Type of the one skeleton graph stored inside the Rips complex structure. + */ + typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS + , boost::property < vertex_filtration_t, Filtration_value > + , boost::property < edge_filtration_t, Filtration_value >> OneSkeletonGraph; + + private: + typedef int Vertex_handle; + + public: + /** \brief Rips_complex constructor from a list of points. + * + * @param[in] points Range of points. + * @param[in] threshold Rips value. + * @param[in] distance distance function that returns a `Filtration_value` from 2 given points. + * + * \tparam ForwardPointRange must be a range for which `std::begin` and `std::end` return input iterators on a + * point. + * + * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where + * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. + */ + template + Rips_complex(const ForwardPointRange& points, Filtration_value threshold, Distance distance) { + compute_proximity_graph(points, threshold, distance); + } + + /** \brief Rips_complex constructor from a distance matrix. + * + * @param[in] distance_matrix Range of distances. + * @param[in] threshold Rips value. + * + * \tparam DistanceMatrix must have a `size()` method and on which `distance_matrix[i][j]` returns + * the distance between points \f$i\f$ and \f$j\f$ as long as \f$ 0 \leqslant i < j \leqslant + * distance\_matrix.size().\f$ + */ + template + Rips_complex(const DistanceMatrix& distance_matrix, Filtration_value threshold) { + compute_proximity_graph(boost::irange((size_t)0, distance_matrix.size()), threshold, + [&](size_t i, size_t j){return distance_matrix[j][i];}); + } + + /** \brief Initializes the simplicial complex from the Rips graph and expands it until a given maximal + * dimension. + * + * \tparam SimplicialComplexForRips must meet `SimplicialComplexForRips` concept. + * + * @param[in] complex SimplicialComplexForRips to be created. + * @param[in] dim_max graph expansion for Rips until this given maximal dimension. + * @exception std::invalid_argument In debug mode, if `complex.num_vertices()` does not return 0. + * + */ + template + void create_complex(SimplicialComplexForRips& complex, int dim_max) { + GUDHI_CHECK(complex.num_vertices() == 0, + std::invalid_argument("Rips_complex::create_complex - simplicial complex is not empty")); + + // insert the proximity graph in the simplicial complex + complex.insert_graph(rips_skeleton_graph_); + // expand the graph until dimension dim_max + complex.expansion(dim_max); + } + + private: + /** \brief Computes the proximity graph of the points. + * + * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the + * distance function between points u and v is smaller than threshold. + * + * \tparam ForwardPointRange furnishes `.begin()` and `.end()` + * methods. + * + * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where + * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. + */ + template< typename ForwardPointRange, typename Distance > + void compute_proximity_graph(const ForwardPointRange& points, Filtration_value threshold, + Distance distance) { + std::vector< std::pair< Vertex_handle, Vertex_handle > > edges; + std::vector< Filtration_value > edges_fil; + + // Compute the proximity graph of the points. + // If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the + // distance function between points u and v is smaller than threshold. + // -------------------------------------------------------------------------------------------- + // Creates the vector of edges and its filtration values (returned by distance function) + Vertex_handle idx_u = 0; + for (auto it_u = std::begin(points); it_u != std::end(points); ++it_u, ++idx_u) { + Vertex_handle idx_v = idx_u + 1; + for (auto it_v = it_u + 1; it_v != std::end(points); ++it_v, ++idx_v) { + Filtration_value fil = distance(*it_u, *it_v); + if (fil <= threshold) { + edges.emplace_back(idx_u, idx_v); + edges_fil.push_back(fil); + } + } + } + + // -------------------------------------------------------------------------------------------- + // Creates the proximity graph from edges and sets the property with the filtration value. + // Number of points is labeled from 0 to idx_u-1 + // -------------------------------------------------------------------------------------------- + // Do not use : rips_skeleton_graph_ = OneSkeletonGraph(...) -> deep copy of the graph (boost graph is not + // move-enabled) + rips_skeleton_graph_.~OneSkeletonGraph(); + new(&rips_skeleton_graph_)OneSkeletonGraph(edges.begin(), edges.end(), edges_fil.begin(), idx_u); + + auto vertex_prop = boost::get(vertex_filtration_t(), rips_skeleton_graph_); + + using vertex_iterator = typename boost::graph_traits::vertex_iterator; + vertex_iterator vi, vi_end; + for (std::tie(vi, vi_end) = boost::vertices(rips_skeleton_graph_); + vi != vi_end; ++vi) { + boost::put(vertex_prop, *vi, 0.); + } + } + + private: + OneSkeletonGraph rips_skeleton_graph_; +}; + +} // namespace rips_complex + +} // namespace Gudhi + +#endif // RIPS_COMPLEX_H_ diff --git a/include/gudhi/Simplex_tree.h b/include/gudhi/Simplex_tree.h index 63e3f0e5..317bce23 100644 --- a/include/gudhi/Simplex_tree.h +++ b/include/gudhi/Simplex_tree.h @@ -1029,7 +1029,7 @@ class Simplex_tree { Dictionary_it next = siblings->members().begin(); ++next; - static std::vector > inter; // static, not thread-safe. + thread_local std::vector > inter; for (Dictionary_it s_h = siblings->members().begin(); s_h != siblings->members().end(); ++s_h, ++next) { Simplex_handle root_sh = find_vertex(s_h->first); diff --git a/include/gudhi/Skeleton_blocker.h b/include/gudhi/Skeleton_blocker.h index 822282fd..32fe411c 100644 --- a/include/gudhi/Skeleton_blocker.h +++ b/include/gudhi/Skeleton_blocker.h @@ -1,24 +1,24 @@ - /* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * - * Author(s): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef SKELETON_BLOCKER_H_ #define SKELETON_BLOCKER_H_ @@ -37,11 +37,12 @@ namespace Gudhi { namespace skeleton_blocker { -/** \defgroup skbl Skeleton-Blocker +/** \defgroup skbl Skeleton-Blocker +@{ \author David Salinas -\section Introduction +\section skblintroduction Introduction The Skeleton-Blocker data-structure proposes a light encoding for simplicial complexes by storing only an *implicit* representation of its simplices \cite socg_blockers_2011,\cite blockers2012. @@ -52,7 +53,7 @@ This data-structure handles all simplicial complexes operations such as are operations that do not require simplex enumeration such as edge iteration, link computation or simplex contraction. -\section Definitions +\section skbldefinitions Definitions We recall briefly classical definitions of simplicial complexes \cite Munkres-elementsalgtop1984. @@ -63,7 +64,7 @@ when \f$ \tau \neq \sigma\f$ we say that \f$ \tau\f$ is a proper-face of \f$ \si An abstract simplicial complex is a set of simplices that contains all the faces of its simplices. The 1-skeleton of a simplicial complex (or its graph) consists of its elements of dimension lower than 2. -*\image html "ds_representation.png" "Skeleton-blocker representation" width=20cm + *\image html "ds_representation.png" "Skeleton-blocker representation" width=20cm To encode, a simplicial complex, one can encodes all its simplices. @@ -85,7 +86,7 @@ in next figure. Storing the graph and blockers of such simplicial complexes is m their simplices. -*\image html "blockers_curve.png" "Number of blockers of random triangulations of 3-spheres" width=10cm + *\image html "blockers_curve.png" "Number of blockers of random triangulations of 3-spheres" width=10cm @@ -107,7 +108,7 @@ and point access in addition. -\subsection Visitor +\subsection skblvisitor Visitor The class Skeleton_blocker_complex has a visitor that is called when usual operations such as adding an edge or remove a vertex are called. You may want to use this visitor to compute statistics or to update another data-structure (for instance this visitor is heavily used in the \ref contr package). @@ -115,7 +116,7 @@ You may want to use this visitor to compute statistics or to update another data -\section Example +\section skblexample Example \subsection Iterating Iterating through vertices, edges, blockers and simplices @@ -127,46 +128,46 @@ such as the Simplex Tree. The following example computes the Euler Characteristi of a simplicial complex. \code{.cpp} - typedef Skeleton_blocker_complex Complex; - typedef Complex::Vertex_handle Vertex_handle; - typedef Complex::Simplex Simplex; - - const int n = 15; - - // build a full complex with 10 vertices and 2^n-1 simplices - Complex complex; - for(int i=0;i Complex; + typedef Complex::Vertex_handle Vertex_handle; + typedef Complex::Simplex Simplex; + + const int n = 15; + + // build a full complex with 10 vertices and 2^n-1 simplices + Complex complex; + for(int i=0;i simplices; - - //add 4 triangles of a tetrahedron 0123 - simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); - simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); - simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2))); - simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1))); - - Complex complex; - //get complex from top faces - make_complex_from_top_faces(complex,simplices.begin(),simplices.end()); - - std::cout << "Simplices:"< simplices; + + //add 4 triangles of a tetrahedron 0123 + simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3))); + simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2))); + simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1))); + + Complex complex; + //get complex from top faces + make_complex_from_top_faces(complex,simplices.begin(),simplices.end()); + + std::cout << "Simplices:"<. */ + #ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ #define SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_ @@ -27,7 +28,7 @@ namespace Gudhi { namespace skeleton_blocker { -// todo rajouter les const +// TODO(DS): to be constified /** *@class Skeleton_blocker_complex_visitor @@ -36,7 +37,7 @@ namespace skeleton_blocker { template class Skeleton_blocker_complex_visitor { public: - virtual ~Skeleton_blocker_complex_visitor() {} + virtual ~Skeleton_blocker_complex_visitor() { } virtual void on_add_vertex(Vertex_handle) = 0; virtual void on_remove_vertex(Vertex_handle) = 0; @@ -61,9 +62,9 @@ class Skeleton_blocker_complex_visitor { virtual void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) = 0; virtual void on_add_blocker( - const Skeleton_blocker_simplex&) = 0; + const Skeleton_blocker_simplex&) = 0; virtual void on_delete_blocker( - const Skeleton_blocker_simplex*) = 0; + const Skeleton_blocker_simplex*) = 0; }; /** @@ -73,24 +74,23 @@ class Skeleton_blocker_complex_visitor { */ template class Dummy_complex_visitor : public Skeleton_blocker_complex_visitor< - Vertex_handle> { +Vertex_handle> { public: - void on_add_vertex(Vertex_handle) { - } - void on_remove_vertex(Vertex_handle) { - } - void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { - } - void on_remove_edge(Vertex_handle a, Vertex_handle b) { - } - void on_changed_edge(Vertex_handle a, Vertex_handle b) { - } - void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { - } - void on_add_blocker(const Skeleton_blocker_simplex&) { - } - void on_delete_blocker(const Skeleton_blocker_simplex*) { - } + void on_add_vertex(Vertex_handle) { } + + void on_remove_vertex(Vertex_handle) { } + + void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { } + + void on_remove_edge(Vertex_handle a, Vertex_handle b) { } + + void on_changed_edge(Vertex_handle a, Vertex_handle b) { } + + void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { } + + void on_add_blocker(const Skeleton_blocker_simplex&) { } + + void on_delete_blocker(const Skeleton_blocker_simplex*) { } }; /** @@ -100,29 +100,36 @@ class Dummy_complex_visitor : public Skeleton_blocker_complex_visitor< */ template class Print_complex_visitor : public Skeleton_blocker_complex_visitor< - Vertex_handle> { +Vertex_handle> { public: void on_add_vertex(Vertex_handle v) { std::cerr << "on_add_vertex:" << v << std::endl; } + void on_remove_vertex(Vertex_handle v) { std::cerr << "on_remove_vertex:" << v << std::endl; } + void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { std::cerr << "on_add_edge_without_blockers:" << a << "," << b << std::endl; } + void on_remove_edge(Vertex_handle a, Vertex_handle b) { std::cerr << "on_remove_edge:" << a << "," << b << std::endl; } + void on_changed_edge(Vertex_handle a, Vertex_handle b) { std::cerr << "on_changed_edge:" << a << "," << b << std::endl; } + void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { std::cerr << "on_swaped_edge:" << a << "," << b << "," << x << std::endl; } + void on_add_blocker(const Skeleton_blocker_simplex& b) { std::cerr << "on_add_blocker:" << b << std::endl; } + void on_delete_blocker(const Skeleton_blocker_simplex* b) { std::cerr << "on_delete_blocker:" << b << std::endl; } diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h index 3bfb5d11..d4b60613 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ #define SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_ @@ -36,7 +37,7 @@ template class Skeleton_blocker_sub_complex; */ template class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex< - ComplexType> { +ComplexType> { typedef typename ComplexType::Edge_handle Edge_handle; typedef typename ComplexType::boost_vertex_handle boost_vertex_handle; @@ -54,20 +55,17 @@ class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex< typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator IdSimplexConstIterator; Skeleton_blocker_link_superior() - : Skeleton_blocker_link_complex(true) { - } + : Skeleton_blocker_link_complex(true) { } Skeleton_blocker_link_superior(const ComplexType & parent_complex, Simplex& alpha_parent_adress) : Skeleton_blocker_link_complex(parent_complex, - alpha_parent_adress, true) { - } + alpha_parent_adress, true) { } Skeleton_blocker_link_superior(const ComplexType & parent_complex, Vertex_handle a_parent_adress) : Skeleton_blocker_link_complex(parent_complex, - a_parent_adress, true) { - } + a_parent_adress, true) { } }; } // namespace skeleton_blocker diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h index ba46c49e..747e60f1 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ #define SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_ @@ -49,8 +50,8 @@ class Skeleton_blocker_off_flag_visitor_reader { load_only_points_(load_only_points) { } void init(int dim, int num_vertices, int num_faces, int num_edges) { - // todo do an assert to check that this number are correctly read - // todo reserve size for vector points + // TODO(DS): do an assert to check that this number are correctly read + // TODO(DS): reserve size for vector points } void point(const std::vector& point) { @@ -108,7 +109,7 @@ class Skeleton_blocker_off_visitor_reader { void done() { complex_ = make_complex_from_top_faces(maximal_faces_.begin(), maximal_faces_.end(), - points_.begin(), points_.end() ); + points_.begin(), points_.end()); } }; @@ -140,7 +141,7 @@ class Skeleton_blocker_off_reader { } /** - * return true iff reading did not meet problems. + * return true if reading did not meet problems. */ bool is_valid() const { return valid_; diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h index fb4a1106..275376e6 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ #define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_ @@ -39,7 +40,7 @@ namespace skeleton_blocker { */ template struct Skeleton_blocker_simple_geometric_traits : - public Skeleton_blocker_simple_traits { +public Skeleton_blocker_simple_traits { public: typedef GeometryTrait GT; typedef typename GT::Point Point; @@ -57,19 +58,20 @@ struct Skeleton_blocker_simple_geometric_traits : Point& point() { return point_; } + const Point& point() const { return point_; } }; class Simple_geometric_edge : - public Skeleton_blocker_simple_traits::Graph_edge { + public Skeleton_blocker_simple_traits::Graph_edge { int index_; public: Simple_geometric_edge() : Skeleton_blocker_simple_traits::Graph_edge(), - index_(-1) { - } + index_(-1) { } + /** * @brief Allows to modify the index of the edge. * The indices of the edge are used to store heap information @@ -78,6 +80,7 @@ struct Skeleton_blocker_simple_geometric_traits : int& index() { return index_; } + int index() const { return index_; } diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h index 31bec3b6..3835cf77 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ #define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_ @@ -48,9 +49,9 @@ struct Skeleton_blocker_simple_traits { */ struct Root_vertex_handle { typedef int boost_vertex_handle; + explicit Root_vertex_handle(boost_vertex_handle val = -1) - : vertex(val) { - } + : vertex(val) { } boost_vertex_handle vertex; bool operator!=(const Root_vertex_handle& other) const { @@ -65,8 +66,8 @@ struct Skeleton_blocker_simple_traits { return this->vertex < other.vertex; } - friend std::ostream& operator <<(std::ostream& o, - const Root_vertex_handle & v) { + friend std::ostream& operator<<(std::ostream& o, + const Root_vertex_handle & v) { o << v.vertex; return o; } @@ -74,11 +75,13 @@ struct Skeleton_blocker_simple_traits { struct Vertex_handle { typedef int boost_vertex_handle; + explicit Vertex_handle(boost_vertex_handle val = -1) - : vertex(val) { - } + : vertex(val) { } - operator int() const { return static_cast(vertex); } + operator int() const { + return static_cast (vertex); + } boost_vertex_handle vertex; @@ -94,7 +97,7 @@ struct Skeleton_blocker_simple_traits { return this->vertex < other.vertex; } - friend std::ostream& operator <<(std::ostream& o, const Vertex_handle & v) { + friend std::ostream& operator<<(std::ostream& o, const Vertex_handle & v) { o << v.vertex; return o; } @@ -105,21 +108,24 @@ struct Skeleton_blocker_simple_traits { Root_vertex_handle id_; public: - virtual ~Graph_vertex() { - } + virtual ~Graph_vertex() { } void activate() { is_active_ = true; } + void deactivate() { is_active_ = false; } + bool is_active() const { return is_active_; } + void set_id(Root_vertex_handle i) { id_ = i; } + Root_vertex_handle get_id() const { return id_; } @@ -130,7 +136,7 @@ struct Skeleton_blocker_simple_traits { return res.str(); } - friend std::ostream& operator <<(std::ostream& o, const Graph_vertex & v) { + friend std::ostream& operator<<(std::ostream& o, const Graph_vertex & v) { o << v.to_string(); return o; } @@ -144,13 +150,13 @@ struct Skeleton_blocker_simple_traits { public: Graph_edge() : a_(-1), - b_(-1), - index_(-1) { - } + b_(-1), + index_(-1) { } int& index() { return index_; } + int index() const { return index_; } @@ -168,7 +174,7 @@ struct Skeleton_blocker_simple_traits { return b_; } - friend std::ostream& operator <<(std::ostream& o, const Graph_edge & v) { + friend std::ostream& operator<<(std::ostream& o, const Graph_edge & v) { o << "(" << v.a_ << "," << v.b_ << " - id = " << v.index(); return o; } diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h index 3c7f1dd5..aa6f2215 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,7 +63,6 @@ class Skeleton_blocker_simplex { */ //@{ - // Skeleton_blocker_simplex():simplex_set() {} void clear() { simplex_set.clear(); } @@ -89,8 +88,7 @@ class Skeleton_blocker_simplex { add_vertex(v); } - void add_vertices() { - } + void add_vertices() { } /** * Initialize a simplex with a string such as {0,1,2} @@ -192,7 +190,6 @@ class Skeleton_blocker_simplex { return simplex_set.crend(); } - typename std::set::iterator begin() { return simplex_set.begin(); } @@ -236,6 +233,7 @@ class Skeleton_blocker_simplex { assert(!empty()); return *(simplex_set.rbegin()); } + /** * @return true iff the simplex contains the simplex a. */ @@ -351,8 +349,8 @@ class Skeleton_blocker_simplex { //@} - friend std::ostream& operator <<(std::ostream& o, - const Skeleton_blocker_simplex & sigma) { + friend std::ostream& operator<<(std::ostream& o, + const Skeleton_blocker_simplex & sigma) { bool first = true; o << "{"; for (auto i : sigma) { diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h index 196fe8c0..fadf6619 100644 --- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h +++ b/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -159,7 +159,7 @@ class Skeleton_blocker_sub_complex : public ComplexType { if (simplex.contains(*blocker)) { Root_simplex_handle blocker_root(parent_complex.get_id(*(blocker))); Simplex blocker_restr( - *(this->get_simplex_address(blocker_root))); + *(this->get_simplex_address(blocker_root))); this->add_blocker(new Simplex(blocker_restr)); } } @@ -190,14 +190,15 @@ class Skeleton_blocker_sub_complex : public ComplexType { // */ // boost::optional get_address(const Root_simplex_handle & s) const; -// private: + // private: /** * same as get_address except that it will return a simplex in any case. * The vertices that were not found are not added. */ // @remark should be private but problem with VS + std::vector > get_addresses( - const Root_simplex_handle & s) const { + const Root_simplex_handle & s) const { std::vector < boost::optional > res; for (auto i : s) { res.push_back(get_address(i)); @@ -214,14 +215,14 @@ class Skeleton_blocker_sub_complex : public ComplexType { */ template bool proper_face_in_union( - Skeleton_blocker_sub_complex & link, - std::vector > & addresses_sigma_in_link, - int vertex_to_be_ignored) { + Skeleton_blocker_sub_complex & link, + std::vector > & addresses_sigma_in_link, + std::size_t vertex_to_be_ignored) { // we test that all vertices of 'addresses_sigma_in_link' but 'vertex_to_be_ignored' // are in link1 if it is the case we construct the corresponding simplex bool vertices_sigma_are_in_link = true; typename ComplexType::Simplex sigma_in_link; - for (int i = 0; i < addresses_sigma_in_link.size(); ++i) { + for (std::size_t i = 0; i < addresses_sigma_in_link.size(); ++i) { if (i != vertex_to_be_ignored) { if (!addresses_sigma_in_link[i]) { vertices_sigma_are_in_link = false; @@ -236,43 +237,24 @@ bool proper_face_in_union( return vertices_sigma_are_in_link && link.contains(sigma_in_link); } -/* - template - bool - proper_faces_in_union(Skeleton_blocker_simplex & sigma, Skeleton_blocker_sub_complex & link1, Skeleton_blocker_sub_complex & link2) - { - typedef typename ComplexType::Vertex_handle Vertex_handle; - std::vector > addresses_sigma_in_link1 = link1.get_addresses(sigma); - std::vector > addresses_sigma_in_link2 = link2.get_addresses(sigma); - - for (int current_index = 0; current_index < addresses_sigma_in_link1.size(); ++current_index) - { - - if (!proper_face_in_union(link1, addresses_sigma_in_link1, current_index) - && !proper_face_in_union(link2, addresses_sigma_in_link2, current_index)){ - return false; - } - } - return true; - }*/ - // Remark: this function should be friend in order to leave get_adresses private // however doing so seemes currently not possible due to a visual studio bug c2668 // "the compiler does not support partial ordering of template functions as specified in the C++ Standard" // http://www.serkey.com/error-c2668-ambiguous-call-to-overloaded-function-bb45ft.html + template bool proper_faces_in_union( - Skeleton_blocker_simplex & sigma, - Skeleton_blocker_sub_complex & link1, - Skeleton_blocker_sub_complex & link2) { + Skeleton_blocker_simplex & sigma, + Skeleton_blocker_sub_complex & link1, + Skeleton_blocker_sub_complex & link2) { typedef typename ComplexType::Vertex_handle Vertex_handle; std::vector < boost::optional > addresses_sigma_in_link1 = link1.get_addresses(sigma); std::vector < boost::optional > addresses_sigma_in_link2 = link2.get_addresses(sigma); - for (int current_index = 0; current_index < addresses_sigma_in_link1.size(); - ++current_index) { + for (std::size_t current_index = 0; current_index < addresses_sigma_in_link1.size(); + ++current_index) { if (!proper_face_in_union(link1, addresses_sigma_in_link1, current_index) && !proper_face_in_union(link2, addresses_sigma_in_link2, current_index)) { @@ -289,4 +271,3 @@ namespace skbl = skeleton_blocker; } // namespace Gudhi #endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_ - diff --git a/include/gudhi/Skeleton_blocker/internal/Top_faces.h b/include/gudhi/Skeleton_blocker/internal/Top_faces.h index 39d95661..2b681752 100644 --- a/include/gudhi/Skeleton_blocker/internal/Top_faces.h +++ b/include/gudhi/Skeleton_blocker/internal/Top_faces.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ #define SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ @@ -69,4 +70,4 @@ namespace skbl = skeleton_blocker; } // namespace Gudhi -#endif // SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ +#endif // SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_ diff --git a/include/gudhi/Skeleton_blocker/internal/Trie.h b/include/gudhi/Skeleton_blocker/internal/Trie.h index cdc47b8a..2c9602fa 100644 --- a/include/gudhi/Skeleton_blocker/internal/Trie.h +++ b/include/gudhi/Skeleton_blocker/internal/Trie.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,6 @@ * */ - #ifndef SKELETON_BLOCKER_INTERNAL_TRIE_H_ #define SKELETON_BLOCKER_INTERNAL_TRIE_H_ @@ -148,7 +147,7 @@ struct Trie { } void remove_leaf() { - assert(is_leaf); + assert(is_leaf()); if (!is_root()) parent_->childs.erase(this); } @@ -240,7 +239,7 @@ struct Tries { std::vector next_dimension_simplices() const { std::vector res; - while (!to_see_.empty() && to_see_.front()->simplex().dimension() == current_dimension_) { + while (!(to_see_.empty()) && (to_see_.front()->simplex().dimension() == current_dimension_)) { res.emplace_back(to_see_.front()->simplex()); for (auto child : to_see_.front()->childs) to_see_.push_back(child.get()); @@ -257,7 +256,7 @@ struct Tries { private: mutable std::deque to_see_; - mutable unsigned current_dimension_ = 0; + mutable int current_dimension_ = 0; std::vector cofaces_; }; diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h index 4dbc9ed3..d2fff960 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ #define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_ diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h index 15618932..b90dcf34 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_ #define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_ diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h index cc3ed276..1351614f 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h index 3b941be5..2acdb555 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ #define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_ @@ -68,10 +69,11 @@ public boost::iterator_facade < Simplex_around_vertex_iterator link_v; std::shared_ptr trie; - std::list nodes_to_be_seen; // todo deque + // TODO(DS): use a deque instead + std::list nodes_to_be_seen; public: - Simplex_around_vertex_iterator() : complex(0) {} + Simplex_around_vertex_iterator() : complex(0) { } Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) : complex(complex_), @@ -81,15 +83,16 @@ public boost::iterator_facade < Simplex_around_vertex_iterator } private: - // todo return to private Simplex_iterator(const Complex* complex, bool end) : complex_(complex) { set_end(); @@ -306,7 +309,7 @@ public boost::iterator_facade < Simplex_iterator /** * Iterator through the maximal faces of the coboundary of a simplex. - */ + */ template class Simplex_coboundary_iterator : public boost::iterator_facade < Simplex_coboundary_iterator @@ -329,12 +332,12 @@ public boost::iterator_facade < Simplex_coboundary_iteratorvertex_range(); current_vertex = link_vertex_range.begin(); @@ -347,9 +350,9 @@ public boost::iterator_facade < Simplex_coboundary_iteratorconvert_handle_from_another_complex(*link, link_vh); } -public: + public: friend std::ostream& operator<<(std::ostream& stream, const Simplex_coboundary_iterator& sci) { return stream; } @@ -369,8 +372,8 @@ public: // assume that iterator points to the same complex and comes from the same simplex bool equal(const Simplex_coboundary_iterator& other) const { assert(complex == other.complex && sigma == other.sigma); - if(is_end()) return other.is_end(); - if(other.is_end()) return is_end(); + if (is_end()) return other.is_end(); + if (other.is_end()) return is_end(); return *current_vertex == *(other.current_vertex); } @@ -384,13 +387,12 @@ public: return res; } -private: + private: bool is_end() const { return !link || current_vertex == link_vertex_end; } }; - } // namespace skeleton_blocker namespace skbl = skeleton_blocker; diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h index b2dd9a21..736941dd 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ #define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_ @@ -135,7 +136,7 @@ typename SkeletonBlockerComplex::Simplex const Triangle_iterator(const SkeletonBlockerComplex* complex) : complex_(complex), current_vertex_(complex->vertex_range().begin()), - current_triangle_(complex, *current_vertex_), // xxx this line is problematic is the complex is empty + current_triangle_(complex, *current_vertex_), // this line is problematic is the complex is empty is_end_(false) { assert(!complex->empty()); gotoFirstTriangle(); @@ -172,7 +173,8 @@ typename SkeletonBlockerComplex::Simplex const bool both_arent_finished = !is_finished() && !other.is_finished(); // if the two iterators are not finished, they must have the same state return (complex_ == other.complex_) && (both_are_finished || ((both_arent_finished) && - current_vertex_ == other.current_vertex_ && current_triangle_ == other.current_triangle_)); + current_vertex_ == other.current_vertex_ && + current_triangle_ == other.current_triangle_)); } Simplex dereference() const { @@ -183,8 +185,10 @@ typename SkeletonBlockerComplex::Simplex const // goto the next vertex that has a triangle pending or the // end vertex iterator if none exists void goto_next_vertex() { - assert(current_triangle_.finished()); // we mush have consume all triangles passing through the vertex - assert(!is_finished()); // we must not be done + // we must have consume all triangles passing through the vertex + assert(current_triangle_.finished()); + // we must not be done + assert(!is_finished()); ++current_vertex_; diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h index f06cab71..9e9ae961 100644 --- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h +++ b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ #define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ @@ -103,7 +104,7 @@ class Vertex_iterator : public boost::iterator_facade< Vertex_iterator -class Neighbors_vertices_iterator: public boost::iterator_facade < Neighbors_vertices_iterator +class Neighbors_vertices_iterator : public boost::iterator_facade < Neighbors_vertices_iterator , typename SkeletonBlockerComplex::Vertex_handle const , boost::forward_traversal_tag , typename SkeletonBlockerComplex::Vertex_handle const> { @@ -122,9 +123,6 @@ class Neighbors_vertices_iterator: public boost::iterator_facade < Neighbors_ver boost_adjacency_iterator end_; public: - // boost_adjacency_iterator ai, ai_end; - // for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; ++ai) { - Neighbors_vertices_iterator() : complex(NULL) { } Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_) : @@ -157,7 +155,7 @@ class Neighbors_vertices_iterator: public boost::iterator_facade < Neighbors_ver } private: - // todo remove this ugly hack + // TODO(DS): remove this ugly hack void set_end() { current_ = end_; } @@ -170,5 +168,3 @@ namespace skbl = skeleton_blocker; } // namespace Gudhi #endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_ - - diff --git a/include/gudhi/Skeleton_blocker_complex.h b/include/gudhi/Skeleton_blocker_complex.h index 7a6d1d50..4f052ba5 100644 --- a/include/gudhi/Skeleton_blocker_complex.h +++ b/include/gudhi/Skeleton_blocker_complex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -211,7 +211,6 @@ class Skeleton_blocker_complex { add_edge_without_blockers(e.first, e.second); } - template void add_blockers(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) { Tries tries(num_vertices(), simplices_begin, simplices_end); @@ -414,7 +413,8 @@ class Skeleton_blocker_complex { /** */ bool contains_vertex(Vertex_handle u) const { - if (u.vertex < 0 || u.vertex >= boost::num_vertices(skeleton)) + Vertex_handle num_vertices(boost::num_vertices(skeleton)); + if (u.vertex < 0 || u.vertex >= num_vertices) return false; return (*this)[u].is_active(); } @@ -441,11 +441,11 @@ class Skeleton_blocker_complex { * @brief Given an Id return the address of the vertex having this Id in the complex. * @remark For a simplicial complex, the address is the id but it may not be the case for a SubComplex. */ - virtual boost::optional get_address( - Root_vertex_handle id) const { + virtual boost::optional get_address(Root_vertex_handle id) const { boost::optional res; - if (id.vertex < boost::num_vertices(skeleton)) - res = Vertex_handle(id.vertex); // xxx + int num_vertices = boost::num_vertices(skeleton); + if (id.vertex < num_vertices) + res = Vertex_handle(id.vertex); return res; } @@ -560,7 +560,7 @@ class Skeleton_blocker_complex { return res; } - /** + /** * @brief Adds all edges of s in the complex. */ void add_edge(const Simplex& s) { @@ -591,7 +591,6 @@ class Skeleton_blocker_complex { return *edge_handle; } - /** * @brief Adds all edges of s in the complex without adding blockers. */ @@ -844,12 +843,13 @@ class Skeleton_blocker_complex { boost_adjacency_iterator ai, ai_end; for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; ++ai) { + Vertex_handle value(*ai); if (keep_only_superior) { - if (*ai > v.vertex) { - n.add_vertex(Vertex_handle(*ai)); + if (value > v.vertex) { + n.add_vertex(value); } } else { - n.add_vertex(Vertex_handle(*ai)); + n.add_vertex(value); } } } @@ -929,7 +929,7 @@ class Skeleton_blocker_complex { // xxx rename get_address et place un using dans sub_complex boost::optional get_simplex_address( - const Root_simplex_handle& s) const { + const Root_simplex_handle& s) const { boost::optional res; Simplex s_address; @@ -1001,10 +1001,9 @@ class Skeleton_blocker_complex { return std::distance(triangles.begin(), triangles.end()); } - /* * @brief returns the number of simplices of a given dimension in the complex. - */ + */ size_t num_simplices() const { auto simplices = complex_simplex_range(); return std::distance(simplices.begin(), simplices.end()); @@ -1012,8 +1011,8 @@ class Skeleton_blocker_complex { /* * @brief returns the number of simplices of a given dimension in the complex. - */ - size_t num_simplices(unsigned dimension) const { + */ + size_t num_simplices(int dimension) const { // TODO(DS): iterator on k-simplices size_t res = 0; for (const auto& s : complex_simplex_range()) diff --git a/include/gudhi/Skeleton_blocker_geometric_complex.h b/include/gudhi/Skeleton_blocker_geometric_complex.h index 1130ca9f..95331b7a 100644 --- a/include/gudhi/Skeleton_blocker_geometric_complex.h +++ b/include/gudhi/Skeleton_blocker_geometric_complex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ #define SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_ diff --git a/include/gudhi/Skeleton_blocker_link_complex.h b/include/gudhi/Skeleton_blocker_link_complex.h index 1bd66289..4db075b0 100644 --- a/include/gudhi/Skeleton_blocker_link_complex.h +++ b/include/gudhi/Skeleton_blocker_link_complex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_LINK_COMPLEX_H_ #define SKELETON_BLOCKER_LINK_COMPLEX_H_ @@ -39,7 +40,7 @@ template class Skeleton_blocker_sub_complex; */ template class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< - ComplexType> { +ComplexType> { template friend class Skeleton_blocker_link_superior; typedef typename ComplexType::Edge_handle Edge_handle; @@ -60,8 +61,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_handle_iterator; explicit Skeleton_blocker_link_complex(bool only_superior_vertices = false) - : only_superior_vertices_(only_superior_vertices) { - } + : only_superior_vertices_(only_superior_vertices) { } /** * If the parameter only_superior_vertices is true, @@ -95,10 +95,10 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< */ Skeleton_blocker_link_complex(const ComplexType & parent_complex, Edge_handle edge, bool only_superior_vertices = - false) + false) : only_superior_vertices_(only_superior_vertices) { Simplex alpha_simplex(parent_complex.first_vertex(edge), - parent_complex.second_vertex(edge)); + parent_complex.second_vertex(edge)); build_link(parent_complex, alpha_simplex); } @@ -151,7 +151,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< bool only_superior_vertices) { // for a vertex we know exactly the number of vertices of the link (and the size of the corresponding vector this->skeleton.m_vertices.reserve( - parent_complex.degree(alpha_parent_adress)); + parent_complex.degree(alpha_parent_adress)); // For all vertex 'v' in this intersection, we go through all its adjacent blockers. // If one blocker minus 'v' is included in alpha then the vertex is not in the link complex. @@ -169,21 +169,21 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< return; for (auto x_link = this->vertex_range().begin(); - x_link != this->vertex_range().end(); ++x_link) { + x_link != this->vertex_range().end(); ++x_link) { for (auto y_link = x_link; ++y_link != this->vertex_range().end();) { Vertex_handle x_parent = *parent_complex.get_address( - this->get_id(*x_link)); + this->get_id(*x_link)); Vertex_handle y_parent = *parent_complex.get_address( - this->get_id(*y_link)); + this->get_id(*y_link)); if (parent_complex.contains_edge(x_parent, y_parent)) { // we check that there is no blocker subset of alpha passing trough x and y bool new_edge = true; for (auto blocker_parent : parent_complex.const_blocker_range( - x_parent)) { + x_parent)) { if (!is_alpha_blocker || *blocker_parent != alpha_parent_adress) { if (blocker_parent->contains(y_parent)) { new_edge = !(alpha_parent_adress.contains_difference( - *blocker_parent, x_parent, y_parent)); + *blocker_parent, x_parent, y_parent)); if (!new_edge) break; } @@ -201,8 +201,8 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< * corresponding address in 'other_complex'. * It assumes that other_complex have a vertex 'this.get_id(address)' */ - boost::optional give_equivalent_vertex( - const ComplexType & other_complex, Vertex_handle address) const { + boost::optional give_equivalent_vertex(const ComplexType & other_complex, + Vertex_handle address) const { Root_vertex_handle id((*this)[address].get_id()); return other_complex.get_address(id); } @@ -269,7 +269,7 @@ class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex< bool only_vertices = false) { assert(is_alpha_blocker || parent_complex.contains(alpha_parent_adress)); compute_link_vertices(parent_complex, alpha_parent_adress, only_superior_vertices_); - if(!only_vertices) { + if (!only_vertices) { compute_link_edges(parent_complex, alpha_parent_adress, is_alpha_blocker); compute_link_blockers(parent_complex, alpha_parent_adress, is_alpha_blocker); } diff --git a/include/gudhi/Skeleton_blocker_simplifiable_complex.h b/include/gudhi/Skeleton_blocker_simplifiable_complex.h index 171efd4b..544e02e8 100644 --- a/include/gudhi/Skeleton_blocker_simplifiable_complex.h +++ b/include/gudhi/Skeleton_blocker_simplifiable_complex.h @@ -4,7 +4,7 @@ * * Author(s): David Salinas * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #ifndef SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ #define SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_ @@ -33,7 +34,7 @@ namespace Gudhi { namespace skeleton_blocker { /** - * Returns true iff the blocker 'sigma' is popable. + * Returns true if the blocker 'sigma' is popable. * To define popable, let us call 'L' the complex that * consists in the current complex without the blocker 'sigma'. * A blocker 'sigma' is then "popable" if the link of 'sigma' @@ -145,8 +146,7 @@ void Skeleton_blocker_complex::remove_star(Vertex_handle v) { * whenever the dimension of tau is at least 2. */ template -void Skeleton_blocker_complex::update_blockers_after_remove_star_of_vertex_or_edge( - const Simplex& simplex_to_be_removed) { +void Skeleton_blocker_complex::update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed) { std::list blockers_to_update; if (simplex_to_be_removed.empty()) return; @@ -224,8 +224,6 @@ void Skeleton_blocker_complex::add_simplex(const Simplex& sig add_blockers_after_simplex_insertion(sigma); } - - template void Skeleton_blocker_complex::add_blockers_after_simplex_insertion(Simplex sigma) { if (sigma.dimension() < 1) return; @@ -385,7 +383,8 @@ Skeleton_blocker_complex::contract_edge(Vertex_handle a, Vert template void Skeleton_blocker_complex::get_blockers_to_be_added_after_contraction(Vertex_handle a, - Vertex_handle b, std::set& blockers_to_add) { + Vertex_handle b, + std::set& blockers_to_add) { blockers_to_add.clear(); typedef Skeleton_blocker_link_complex > LinkComplexType; diff --git a/include/gudhi/Strong_witness_complex.h b/include/gudhi/Strong_witness_complex.h new file mode 100644 index 00000000..a973ddb7 --- /dev/null +++ b/include/gudhi/Strong_witness_complex.h @@ -0,0 +1,185 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2015 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef STRONG_WITNESS_COMPLEX_H_ +#define STRONG_WITNESS_COMPLEX_H_ + +#include + +#include +#include +#include +#include + +namespace Gudhi { + +namespace witness_complex { + +/* \private + * \class Strong_witness_complex + * \brief Constructs strong witness complex for a given table of nearest landmarks with respect to witnesses. + * \ingroup witness_complex + * + * \tparam Nearest_landmark_table_ needs to be a range of a range of pairs of nearest landmarks and distances. + * The class Nearest_landmark_table_::value_type must be a copiable range. + * The range of pairs must admit a member type 'iterator'. The dereference type + * of the pair range iterator needs to be 'std::pair'. + */ +template< class Nearest_landmark_table_ > +class Strong_witness_complex { + private: + typedef typename Nearest_landmark_table_::value_type Nearest_landmark_range; + typedef std::size_t Witness_id; + typedef std::size_t Landmark_id; + typedef std::pair Id_distance_pair; + typedef Active_witness ActiveWitness; + typedef std::list< ActiveWitness > ActiveWitnessList; + typedef std::vector< Landmark_id > typeVectorVertex; + typedef std::vector Nearest_landmark_table_internal; + typedef Landmark_id Vertex_handle; + + protected: + Nearest_landmark_table_internal nearest_landmark_table_; + + public: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* @name Constructor + */ + + //@{ + + Strong_witness_complex() { + } + + /** + * \brief Initializes member variables before constructing simplicial complex. + * \details Records nearest landmark table. + * @param[in] nearest_landmark_table needs to be a range of a range of pairs of nearest landmarks and distances. + * The class Nearest_landmark_table_::value_type must be a copiable range. + * The range of pairs must admit a member type 'iterator'. The dereference type + * of the pair range iterator needs to be 'std::pair'. + */ + Strong_witness_complex(Nearest_landmark_table_ const & nearest_landmark_table) + : nearest_landmark_table_(std::begin(nearest_landmark_table), std::end(nearest_landmark_table)) { + } + + /** \brief Outputs the strong witness complex of relaxation 'max_alpha_square' + * in a simplicial complex data structure. + * \details The function returns true if the construction is successful and false otherwise. + * @param[out] complex Simplicial complex data structure, which is a model of + * SimplicialComplexForWitness concept. + * @param[in] max_alpha_square Maximal squared relaxation parameter. + * @param[in] limit_dimension Represents the maximal dimension of the simplicial complex + * (default value = no limit). + */ + template < typename SimplicialComplexForWitness > + bool create_complex(SimplicialComplexForWitness& complex, + double max_alpha_square, + Landmark_id limit_dimension = std::numeric_limits::max()) const { + Landmark_id complex_dim = 0; + if (complex.num_vertices() > 0) { + std::cerr << "Strong witness complex cannot create complex - complex is not empty.\n"; + return false; + } + if (max_alpha_square < 0) { + std::cerr << "Strong witness complex cannot create complex - squared relaxation parameter must be " + << "non-negative.\n"; + return false; + } + if (limit_dimension < 0) { + std::cerr << "Strong witness complex cannot create complex - limit dimension must be non-negative.\n"; + return false; + } + for (auto w : nearest_landmark_table_) { + ActiveWitness aw(w); + typeVectorVertex simplex; + typename ActiveWitness::iterator aw_it = aw.begin(); + float lim_dist2 = aw.begin()->second + max_alpha_square; + while ((Landmark_id)simplex.size() <= limit_dimension && aw_it != aw.end() && aw_it->second < lim_dist2) { + simplex.push_back(aw_it->first); + complex.insert_simplex_and_subfaces(simplex, aw_it->second - aw.begin()->second); + aw_it++; + } + // continue inserting limD-faces of the following simplices + typeVectorVertex& vertices = simplex; // 'simplex' now will be called vertices + while (aw_it != aw.end() && aw_it->second < lim_dist2) { + typeVectorVertex facet = {}; + add_all_faces_of_dimension(limit_dimension, vertices, vertices.begin(), aw_it, + aw_it->second - aw.begin()->second, facet, complex); + vertices.push_back(aw_it->first); + aw_it++; + } + if ((Landmark_id)simplex.size() - 1 > complex_dim) + complex_dim = simplex.size() - 1; + } + complex.set_dimension(complex_dim); + return true; + } + + private: + /* \brief Adds recursively all the faces of a certain dimension dim-1 witnessed by the same witness. + * Iterator is needed to know until how far we can take landmarks to form simplexes. + * simplex is the prefix of the simplexes to insert. + * The landmark pointed by aw_it is added to all formed simplices. + */ + template < typename SimplicialComplexForWitness > + void add_all_faces_of_dimension(Landmark_id dim, + typeVectorVertex& vertices, + typename typeVectorVertex::iterator curr_it, + typename ActiveWitness::iterator aw_it, + double filtration_value, + typeVectorVertex& simplex, + SimplicialComplexForWitness& sc) const { + if (dim > 0) { + while (curr_it != vertices.end()) { + simplex.push_back(*curr_it); + ++curr_it; + add_all_faces_of_dimension(dim-1, + vertices, + curr_it, + aw_it, + filtration_value, + simplex, + sc); + simplex.pop_back(); + add_all_faces_of_dimension(dim, + vertices, + curr_it, + aw_it, + filtration_value, + simplex, + sc); + } + } else if (dim == 0) { + simplex.push_back(aw_it->first); + sc.insert_simplex_and_subfaces(simplex, filtration_value); + simplex.pop_back(); + } + } + //@} +}; + +} // namespace witness_complex + +} // namespace Gudhi + +#endif // STRONG_WITNESS_COMPLEX_H_ diff --git a/include/gudhi/Tangential_complex.h b/include/gudhi/Tangential_complex.h new file mode 100644 index 00000000..cfc82eb1 --- /dev/null +++ b/include/gudhi/Tangential_complex.h @@ -0,0 +1,2276 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TANGENTIAL_COMPLEX_H_ +#define TANGENTIAL_COMPLEX_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // for CGAL::Identity +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for std::sqrt +#include +#include // for std::size_t + +#ifdef GUDHI_USE_TBB +#include +#include +#include +#endif + +// #define GUDHI_TC_EXPORT_NORMALS // Only for 3D surfaces (k=2, d=3) + +namespace sps = Gudhi::spatial_searching; + +namespace Gudhi { + +namespace tangential_complex { + +using namespace internal; + +class Vertex_data { + public: + Vertex_data(std::size_t data = (std::numeric_limits::max)()) + : m_data(data) { } + + operator std::size_t() { + return m_data; + } + + operator std::size_t() const { + return m_data; + } + + private: + std::size_t m_data; +}; + +/** + * \class Tangential_complex Tangential_complex.h gudhi/Tangential_complex.h + * \brief Tangential complex data structure. + * + * \ingroup tangential_complex + * + * \details + * The class Tangential_complex represents a tangential complex. + * After the computation of the complex, an optional post-processing called perturbation can + * be run to attempt to remove inconsistencies. + * + * \tparam Kernel_ requires a CGAL::Epick_d class, which + * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't. + * \tparam DimensionTag can be either Dimension_tag + * if you know the intrinsic dimension at compile-time, + * or CGAL::Dynamic_dimension_tag + * if you don't. + * \tparam Concurrency_tag enables sequential versus parallel computation. Possible values are `CGAL::Parallel_tag` (the default) and `CGAL::Sequential_tag`. + * \tparam Triangulation_ is the type used for storing the local regular triangulations. We highly recommend to use the default value (`CGAL::Regular_triangulation`). + * + */ +template +< + typename Kernel_, // ambiant kernel + typename DimensionTag, // intrinsic dimension + typename Concurrency_tag = CGAL::Parallel_tag, + typename Triangulation_ = CGAL::Default +> +class Tangential_complex { + typedef Kernel_ K; + typedef typename K::FT FT; + typedef typename K::Point_d Point; + typedef typename K::Weighted_point_d Weighted_point; + typedef typename K::Vector_d Vector; + + typedef typename CGAL::Default::Get + < + Triangulation_, + CGAL::Regular_triangulation + < + CGAL::Epick_d, + CGAL::Triangulation_data_structure + < + typename CGAL::Epick_d::Dimension, + CGAL::Triangulation_vertex + < + CGAL::Regular_triangulation_traits_adapter< CGAL::Epick_d >, Vertex_data + >, + CGAL::Triangulation_full_cell > > + > + > + >::type Triangulation; + typedef typename Triangulation::Geom_traits Tr_traits; + typedef typename Triangulation::Weighted_point Tr_point; + typedef typename Triangulation::Bare_point Tr_bare_point; + typedef typename Triangulation::Vertex_handle Tr_vertex_handle; + typedef typename Triangulation::Full_cell_handle Tr_full_cell_handle; + typedef typename Tr_traits::Vector_d Tr_vector; + +#if defined(GUDHI_USE_TBB) + typedef tbb::mutex Mutex_for_perturb; + typedef Vector Translation_for_perturb; + typedef std::vector > Weights; +#else + typedef Vector Translation_for_perturb; + typedef std::vector Weights; +#endif + typedef std::vector Translations_for_perturb; + + // Store a local triangulation and a handle to its center vertex + + struct Tr_and_VH { + public: + Tr_and_VH() + : m_tr(NULL) { } + + Tr_and_VH(int dim) + : m_tr(new Triangulation(dim)) { } + + ~Tr_and_VH() { + destroy_triangulation(); + } + + Triangulation & construct_triangulation(int dim) { + delete m_tr; + m_tr = new Triangulation(dim); + return tr(); + } + + void destroy_triangulation() { + delete m_tr; + m_tr = NULL; + } + + Triangulation & tr() { + return *m_tr; + } + + Triangulation const& tr() const { + return *m_tr; + } + + Tr_vertex_handle const& center_vertex() const { + return m_center_vertex; + } + + Tr_vertex_handle & center_vertex() { + return m_center_vertex; + } + + private: + Triangulation* m_tr; + Tr_vertex_handle m_center_vertex; + }; + + public: + typedef Basis Tangent_space_basis; + typedef Basis Orthogonal_space_basis; + typedef std::vector TS_container; + typedef std::vector OS_container; + + typedef std::vector Points; + + typedef boost::container::flat_set Simplex; + typedef std::set Simplex_set; + + private: + typedef sps::Kd_tree_search Points_ds; + typedef typename Points_ds::KNS_range KNS_range; + typedef typename Points_ds::INS_range INS_range; + + typedef std::vector Tr_container; + typedef std::vector Vectors; + + // An Incident_simplex is the list of the vertex indices + // except the center vertex + typedef boost::container::flat_set Incident_simplex; + typedef std::vector Star; + typedef std::vector Stars_container; + + // For transform_iterator + + static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) { + return vh->point(); + } + + template + static const P &vertex_handle_to_point(VH vh) { + return vh->point(); + } + + public: + typedef internal::Simplicial_complex Simplicial_complex; + + /** \brief Constructor from a range of points. + * Points are copied into the instance, and a search data structure is initialized. + * Note the complex is not computed: `compute_tangential_complex` must be called after the creation + * of the object. + * + * @param[in] points Range of points (`Point_range::value_type` must be the same as `Kernel_::Point_d`). + * @param[in] intrinsic_dimension Intrinsic dimension of the manifold. + * @param[in] k Kernel instance. + */ + template + Tangential_complex(Point_range points, + int intrinsic_dimension, +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + InputIterator first_for_tse, InputIterator last_for_tse, +#endif + const K &k = K() + ) + : m_k(k), + m_intrinsic_dim(intrinsic_dimension), + m_ambient_dim(points.empty() ? 0 : k.point_dimension_d_object()(*points.begin())), + m_points(points.begin(), points.end()), + m_weights(m_points.size(), FT(0)) +#if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION) + , m_p_perturb_mutexes(NULL) +#endif + , m_points_ds(m_points) + , m_last_max_perturb(0.) + , m_are_tangent_spaces_computed(m_points.size(), false) + , m_tangent_spaces(m_points.size(), Tangent_space_basis()) +#ifdef GUDHI_TC_EXPORT_NORMALS + , m_orth_spaces(m_points.size(), Orthogonal_space_basis()) +#endif +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + , m_points_for_tse(first_for_tse, last_for_tse) + , m_points_ds_for_tse(m_points_for_tse) +#endif + { } + + /// Destructor + ~Tangential_complex() { +#if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION) + delete [] m_p_perturb_mutexes; +#endif + } + + /// Returns the intrinsic dimension of the manifold. + int intrinsic_dimension() const { + return m_intrinsic_dim; + } + + /// Returns the ambient dimension. + int ambient_dimension() const { + return m_ambient_dim; + } + + Points const& points() const { + return m_points; + } + + /** \brief Returns the point corresponding to the vertex given as parameter. + * + * @param[in] vertex Vertex handle of the point to retrieve. + * @return The point found. + */ + Point get_point(std::size_t vertex) const { + return m_points[vertex]; + } + + /** \brief Returns the perturbed position of the point corresponding to the vertex given as parameter. + * + * @param[in] vertex Vertex handle of the point to retrieve. + * @return The perturbed position of the point found. + */ + Point get_perturbed_point(std::size_t vertex) const { + return compute_perturbed_point(vertex); + } + + /// Returns the number of vertices. + + std::size_t number_of_vertices() const { + return m_points.size(); + } + + void set_weights(const Weights& weights) { + m_weights = weights; + } + + void set_tangent_planes(const TS_container& tangent_spaces +#ifdef GUDHI_TC_EXPORT_NORMALS + , const OS_container& orthogonal_spaces +#endif + ) { +#ifdef GUDHI_TC_EXPORT_NORMALS + GUDHI_CHECK( + m_points.size() == tangent_spaces.size() + && m_points.size() == orthogonal_spaces.size(), + std::logic_error("Wrong sizes")); +#else + GUDHI_CHECK( + m_points.size() == tangent_spaces.size(), + std::logic_error("Wrong sizes")); +#endif + m_tangent_spaces = tangent_spaces; +#ifdef GUDHI_TC_EXPORT_NORMALS + m_orth_spaces = orthogonal_spaces; +#endif + for (std::size_t i = 0; i < m_points.size(); ++i) + m_are_tangent_spaces_computed[i] = true; + } + + /// Computes the tangential complex. + void compute_tangential_complex() { +#ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS + std::cerr << red << "WARNING: GUDHI_TC_PERFORM_EXTRA_CHECKS is defined. " + << "Computation might be slower than usual.\n" << white; +#endif + +#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB) + Gudhi::Clock t; +#endif + + // We need to do that because we don't want the container to copy the + // already-computed triangulations (while resizing) since it would + // invalidate the vertex handles stored beside the triangulations + m_triangulations.resize(m_points.size()); + m_stars.resize(m_points.size()); + m_squared_star_spheres_radii_incl_margin.resize(m_points.size(), FT(-1)); +#ifdef GUDHI_TC_PERTURB_POSITION + if (m_points.empty()) + m_translations.clear(); + else + m_translations.resize(m_points.size(), + m_k.construct_vector_d_object()(m_ambient_dim)); +#if defined(GUDHI_USE_TBB) + delete [] m_p_perturb_mutexes; + m_p_perturb_mutexes = new Mutex_for_perturb[m_points.size()]; +#endif +#endif + +#ifdef GUDHI_USE_TBB + // Parallel + if (boost::is_convertible::value) { + tbb::parallel_for(tbb::blocked_range(0, m_points.size()), + Compute_tangent_triangulation(*this)); + } else { +#endif // GUDHI_USE_TBB + // Sequential + for (std::size_t i = 0; i < m_points.size(); ++i) + compute_tangent_triangulation(i); +#ifdef GUDHI_USE_TBB + } +#endif // GUDHI_USE_TBB + +#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB) + t.end(); + std::cerr << "Tangential complex computed in " << t.num_seconds() + << " seconds.\n"; +#endif + } + + /// \brief Type returned by `Tangential_complex::fix_inconsistencies_using_perturbation`. + struct Fix_inconsistencies_info { + /// `true` if all inconsistencies could be removed, `false` if the time limit has been reached before + bool success = false; + /// number of steps performed + unsigned int num_steps = 0; + /// initial number of inconsistent stars + std::size_t initial_num_inconsistent_stars = 0; + /// best number of inconsistent stars during the process + std::size_t best_num_inconsistent_stars = 0; + /// final number of inconsistent stars + std::size_t final_num_inconsistent_stars = 0; + }; + + /** \brief Attempts to fix inconsistencies by perturbing the point positions. + * + * @param[in] max_perturb Maximum length of the translations used by the perturbation. + * @param[in] time_limit Time limit in seconds. If -1, no time limit is set. + */ + Fix_inconsistencies_info fix_inconsistencies_using_perturbation(double max_perturb, double time_limit = -1.) { + Fix_inconsistencies_info info; + + if (time_limit == 0.) + return info; + + Gudhi::Clock t; + +#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES + std::tuple stats_before = + number_of_inconsistent_simplices(false); + + if (std::get<1>(stats_before) == 0) { +#ifdef DEBUG_TRACES + std::cerr << "Nothing to fix.\n"; +#endif + info.success = false; + return info; + } +#endif // GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES + + m_last_max_perturb = max_perturb; + + bool done = false; + info.best_num_inconsistent_stars = m_triangulations.size(); + info.num_steps = 0; + while (!done) { +#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES + std::cerr + << "\nBefore fix step:\n" + << " * Total number of simplices in stars (incl. duplicates): " + << std::get<0>(stats_before) << "\n" + << " * Num inconsistent simplices in stars (incl. duplicates): " + << red << std::get<1>(stats_before) << white << " (" + << 100. * std::get<1>(stats_before) / std::get<0>(stats_before) << "%)\n" + << " * Number of stars containing inconsistent simplices: " + << red << std::get<2>(stats_before) << white << " (" + << 100. * std::get<2>(stats_before) / m_points.size() << "%)\n"; +#endif + +#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) + std::cerr << yellow + << "\nAttempt to fix inconsistencies using perturbations - step #" + << info.num_steps + 1 << "... " << white; +#endif + + std::size_t num_inconsistent_stars = 0; + std::vector updated_points; + +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t_fix_step; +#endif + + // Parallel +#if defined(GUDHI_USE_TBB) + if (boost::is_convertible::value) { + tbb::combinable num_inconsistencies; + tbb::combinable > tls_updated_points; + tbb::parallel_for( + tbb::blocked_range(0, m_triangulations.size()), + Try_to_solve_inconsistencies_in_a_local_triangulation(*this, max_perturb, + num_inconsistencies, + tls_updated_points)); + num_inconsistent_stars = + num_inconsistencies.combine(std::plus()); + updated_points = tls_updated_points.combine( + [](std::vector const& x, + std::vector const& y) { + std::vector res; + res.reserve(x.size() + y.size()); + res.insert(res.end(), x.begin(), x.end()); + res.insert(res.end(), y.begin(), y.end()); + return res; + }); + } else { +#endif // GUDHI_USE_TBB + // Sequential + for (std::size_t i = 0; i < m_triangulations.size(); ++i) { + num_inconsistent_stars += + try_to_solve_inconsistencies_in_a_local_triangulation(i, max_perturb, + std::back_inserter(updated_points)); + } +#if defined(GUDHI_USE_TBB) + } +#endif // GUDHI_USE_TBB + +#ifdef GUDHI_TC_PROFILING + t_fix_step.end(); +#endif + +#if defined(GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES) || defined(DEBUG_TRACES) + std::cerr + << "\nEncountered during fix:\n" + << " * Num stars containing inconsistent simplices: " + << red << num_inconsistent_stars << white + << " (" << 100. * num_inconsistent_stars / m_points.size() << "%)\n"; +#endif + +#ifdef GUDHI_TC_PROFILING + std::cerr << yellow << "done in " << t_fix_step.num_seconds() + << " seconds.\n" << white; +#elif defined(DEBUG_TRACES) + std::cerr << yellow << "done.\n" << white; +#endif + + if (num_inconsistent_stars > 0) + refresh_tangential_complex(updated_points); + +#ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS + // Confirm that all stars were actually refreshed + std::size_t num_inc_1 = + std::get<1>(number_of_inconsistent_simplices(false)); + refresh_tangential_complex(); + std::size_t num_inc_2 = + std::get<1>(number_of_inconsistent_simplices(false)); + if (num_inc_1 != num_inc_2) + std::cerr << red << "REFRESHMENT CHECK: FAILED. (" + << num_inc_1 << " vs " << num_inc_2 << ")\n" << white; + else + std::cerr << green << "REFRESHMENT CHECK: PASSED.\n" << white; +#endif + +#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES + std::tuple stats_after = + number_of_inconsistent_simplices(false); + + std::cerr + << "\nAfter fix:\n" + << " * Total number of simplices in stars (incl. duplicates): " + << std::get<0>(stats_after) << "\n" + << " * Num inconsistent simplices in stars (incl. duplicates): " + << red << std::get<1>(stats_after) << white << " (" + << 100. * std::get<1>(stats_after) / std::get<0>(stats_after) << "%)\n" + << " * Number of stars containing inconsistent simplices: " + << red << std::get<2>(stats_after) << white << " (" + << 100. * std::get<2>(stats_after) / m_points.size() << "%)\n"; + + stats_before = stats_after; +#endif + + if (info.num_steps == 0) + info.initial_num_inconsistent_stars = num_inconsistent_stars; + + if (num_inconsistent_stars < info.best_num_inconsistent_stars) + info.best_num_inconsistent_stars = num_inconsistent_stars; + + info.final_num_inconsistent_stars = num_inconsistent_stars; + + done = (num_inconsistent_stars == 0); + if (!done) { + ++info.num_steps; + if (time_limit > 0. && t.num_seconds() > time_limit) { +#ifdef DEBUG_TRACES + std::cerr << red << "Time limit reached.\n" << white; +#endif + info.success = false; + return info; + } + } + } + +#ifdef DEBUG_TRACES + std::cerr << green << "Fixed!\n" << white; +#endif + info.success = true; + return info; + } + + /// \brief Type returned by `Tangential_complex::number_of_inconsistent_simplices`. + struct Num_inconsistencies { + /// Total number of simplices in stars (including duplicates that appear in several stars) + std::size_t num_simplices = 0; + /// Number of inconsistent simplices + std::size_t num_inconsistent_simplices = 0; + /// Number of stars containing at least one inconsistent simplex + std::size_t num_inconsistent_stars = 0; + }; + + /// Returns the number of inconsistencies + /// @param[in] verbose If true, outputs a message into `std::cerr`. + + Num_inconsistencies + number_of_inconsistent_simplices( +#ifdef DEBUG_TRACES + bool verbose = true +#else + bool verbose = false +#endif + ) const { + Num_inconsistencies stats; + + // For each triangulation + for (std::size_t idx = 0; idx < m_points.size(); ++idx) { + bool is_star_inconsistent = false; + + // For each cell + Star::const_iterator it_inc_simplex = m_stars[idx].begin(); + Star::const_iterator it_inc_simplex_end = m_stars[idx].end(); + for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) { + // Don't check infinite cells + if (is_infinite(*it_inc_simplex)) + continue; + + Simplex c = *it_inc_simplex; + c.insert(idx); // Add the missing index + + if (!is_simplex_consistent(c)) { + ++stats.num_inconsistent_simplices; + is_star_inconsistent = true; + } + + ++stats.num_simplices; + } + stats.num_inconsistent_stars += is_star_inconsistent; + } + + if (verbose) { + std::cerr + << "\n==========================================================\n" + << "Inconsistencies:\n" + << " * Total number of simplices in stars (incl. duplicates): " + << stats.num_simplices << "\n" + << " * Number of inconsistent simplices in stars (incl. duplicates): " + << stats.num_inconsistent_simplices << " (" + << 100. * stats.num_inconsistent_simplices / stats.num_simplices << "%)\n" + << " * Number of stars containing inconsistent simplices: " + << stats.num_inconsistent_stars << " (" + << 100. * stats.num_inconsistent_stars / m_points.size() << "%)\n" + << "==========================================================\n"; + } + + return stats; + } + + /** \brief Exports the complex into a Simplex_tree. + * + * \tparam Simplex_tree_ must be a `Simplex_tree`. + * + * @param[out] tree The result, where each `Vertex_handle` is the index of the + * corresponding point in the range provided to the constructor (it can also be + * retrieved through the `Tangential_complex::get_point` function. + * @param[in] export_inconsistent_simplices Also export inconsistent simplices or not? + * @return The maximal dimension of the simplices. + */ + template + int create_complex(Simplex_tree_ &tree + , bool export_inconsistent_simplices = true + /// \cond ADVANCED_PARAMETERS + , bool export_infinite_simplices = false + , Simplex_set *p_inconsistent_simplices = NULL + /// \endcond + ) const { +#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) + std::cerr << yellow + << "\nExporting the TC as a Simplex_tree... " << white; +#endif +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t; +#endif + + int max_dim = -1; + + // For each triangulation + for (std::size_t idx = 0; idx < m_points.size(); ++idx) { + // For each cell of the star + Star::const_iterator it_inc_simplex = m_stars[idx].begin(); + Star::const_iterator it_inc_simplex_end = m_stars[idx].end(); + for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) { + Simplex c = *it_inc_simplex; + + // Don't export infinite cells + if (!export_infinite_simplices && is_infinite(c)) + continue; + + if (!export_inconsistent_simplices && !is_simplex_consistent(c)) + continue; + + if (static_cast (c.size()) > max_dim) + max_dim = static_cast (c.size()); + // Add the missing center vertex + c.insert(idx); + + // Try to insert the simplex + bool inserted = tree.insert_simplex_and_subfaces(c).second; + + // Inconsistent? + if (p_inconsistent_simplices && inserted && !is_simplex_consistent(c)) { + p_inconsistent_simplices->insert(c); + } + } + } + +#ifdef GUDHI_TC_PROFILING + t.end(); + std::cerr << yellow << "done in " << t.num_seconds() + << " seconds.\n" << white; +#elif defined(DEBUG_TRACES) + std::cerr << yellow << "done.\n" << white; +#endif + + return max_dim; + } + + // First clears the complex then exports the TC into it + // Returns the max dimension of the simplices + // check_lower_and_higher_dim_simplices : 0 (false), 1 (true), 2 (auto) + // If the check is enabled, the function: + // - won't insert the simplex if it is already in a higher dim simplex + // - will erase any lower-dim simplices that are faces of the new simplex + // "auto" (= 2) will enable the check as a soon as it encounters a + // simplex whose dimension is different from the previous ones. + // N.B.: The check is quite expensive. + + int create_complex(Simplicial_complex &complex, + bool export_inconsistent_simplices = true, + bool export_infinite_simplices = false, + int check_lower_and_higher_dim_simplices = 2, + Simplex_set *p_inconsistent_simplices = NULL) const { +#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) + std::cerr << yellow + << "\nExporting the TC as a Simplicial_complex... " << white; +#endif +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t; +#endif + + int max_dim = -1; + complex.clear(); + + // For each triangulation + for (std::size_t idx = 0; idx < m_points.size(); ++idx) { + // For each cell of the star + Star::const_iterator it_inc_simplex = m_stars[idx].begin(); + Star::const_iterator it_inc_simplex_end = m_stars[idx].end(); + for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) { + Simplex c = *it_inc_simplex; + + // Don't export infinite cells + if (!export_infinite_simplices && is_infinite(c)) + continue; + + if (!export_inconsistent_simplices && !is_simplex_consistent(c)) + continue; + + // Unusual simplex dim? + if (check_lower_and_higher_dim_simplices == 2 + && max_dim != -1 + && static_cast (c.size()) != max_dim) { + // Let's activate the check + std::cerr << red << + "Info: check_lower_and_higher_dim_simplices ACTIVATED. " + "Export might be take some time...\n" << white; + check_lower_and_higher_dim_simplices = 1; + } + + if (static_cast (c.size()) > max_dim) + max_dim = static_cast (c.size()); + // Add the missing center vertex + c.insert(idx); + + // Try to insert the simplex + bool added = + complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1); + + // Inconsistent? + if (p_inconsistent_simplices && added && !is_simplex_consistent(c)) { + p_inconsistent_simplices->insert(c); + } + } + } + +#ifdef GUDHI_TC_PROFILING + t.end(); + std::cerr << yellow << "done in " << t.num_seconds() + << " seconds.\n" << white; +#elif defined(DEBUG_TRACES) + std::cerr << yellow << "done.\n" << white; +#endif + + return max_dim; + } + + template > + std::ostream &export_to_off( + const Simplicial_complex &complex, std::ostream & os, + Simplex_set const *p_simpl_to_color_in_red = NULL, + Simplex_set const *p_simpl_to_color_in_green = NULL, + Simplex_set const *p_simpl_to_color_in_blue = NULL, + ProjectionFunctor const& point_projection = ProjectionFunctor()) + const { + return export_to_off( + os, false, p_simpl_to_color_in_red, p_simpl_to_color_in_green, + p_simpl_to_color_in_blue, &complex, point_projection); + } + + template > + std::ostream &export_to_off( + std::ostream & os, bool color_inconsistencies = false, + Simplex_set const *p_simpl_to_color_in_red = NULL, + Simplex_set const *p_simpl_to_color_in_green = NULL, + Simplex_set const *p_simpl_to_color_in_blue = NULL, + const Simplicial_complex *p_complex = NULL, + ProjectionFunctor const& point_projection = ProjectionFunctor()) const { + if (m_points.empty()) + return os; + + if (m_ambient_dim < 2) { + std::cerr << "Error: export_to_off => ambient dimension should be >= 2.\n"; + os << "Error: export_to_off => ambient dimension should be >= 2.\n"; + return os; + } + if (m_ambient_dim > 3) { + std::cerr << "Warning: export_to_off => ambient dimension should be " + "<= 3. Only the first 3 coordinates will be exported.\n"; + } + + if (m_intrinsic_dim < 1 || m_intrinsic_dim > 3) { + std::cerr << "Error: export_to_off => intrinsic dimension should be " + "between 1 and 3.\n"; + os << "Error: export_to_off => intrinsic dimension should be " + "between 1 and 3.\n"; + return os; + } + + std::stringstream output; + std::size_t num_simplices, num_vertices; + export_vertices_to_off(output, num_vertices, false, point_projection); + if (p_complex) { + export_simplices_to_off( + *p_complex, output, num_simplices, p_simpl_to_color_in_red, + p_simpl_to_color_in_green, p_simpl_to_color_in_blue); + } else { + export_simplices_to_off( + output, num_simplices, color_inconsistencies, p_simpl_to_color_in_red, + p_simpl_to_color_in_green, p_simpl_to_color_in_blue); + } + +#ifdef GUDHI_TC_EXPORT_NORMALS + os << "N"; +#endif + + os << "OFF \n" + << num_vertices << " " + << num_simplices << " " + << "0 \n" + << output.str(); + + return os; + } + + private: + void refresh_tangential_complex() { +#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) + std::cerr << yellow << "\nRefreshing TC... " << white; +#endif + +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t; +#endif +#ifdef GUDHI_USE_TBB + // Parallel + if (boost::is_convertible::value) { + tbb::parallel_for(tbb::blocked_range(0, m_points.size()), + Compute_tangent_triangulation(*this)); + } else { +#endif // GUDHI_USE_TBB + // Sequential + for (std::size_t i = 0; i < m_points.size(); ++i) + compute_tangent_triangulation(i); +#ifdef GUDHI_USE_TBB + } +#endif // GUDHI_USE_TBB + +#ifdef GUDHI_TC_PROFILING + t.end(); + std::cerr << yellow << "done in " << t.num_seconds() + << " seconds.\n" << white; +#elif defined(DEBUG_TRACES) + std::cerr << yellow << "done.\n" << white; +#endif + } + + // If the list of perturbed points is provided, it is much faster + template + void refresh_tangential_complex( + Point_indices_range const& perturbed_points_indices) { +#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING) + std::cerr << yellow << "\nRefreshing TC... " << white; +#endif + +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t; +#endif + + // ANN tree containing only the perturbed points + Points_ds updated_pts_ds(m_points, perturbed_points_indices); + +#ifdef GUDHI_USE_TBB + // Parallel + if (boost::is_convertible::value) { + tbb::parallel_for(tbb::blocked_range(0, m_points.size()), + Refresh_tangent_triangulation(*this, updated_pts_ds)); + } else { +#endif // GUDHI_USE_TBB + // Sequential + for (std::size_t i = 0; i < m_points.size(); ++i) + refresh_tangent_triangulation(i, updated_pts_ds); +#ifdef GUDHI_USE_TBB + } +#endif // GUDHI_USE_TBB + +#ifdef GUDHI_TC_PROFILING + t.end(); + std::cerr << yellow << "done in " << t.num_seconds() + << " seconds.\n" << white; +#elif defined(DEBUG_TRACES) + std::cerr << yellow << "done.\n" << white; +#endif + } + + void export_inconsistent_stars_to_OFF_files(std::string const& filename_base) const { + // For each triangulation + for (std::size_t idx = 0; idx < m_points.size(); ++idx) { + // We build a SC along the way in case it's inconsistent + Simplicial_complex sc; + // For each cell + bool is_inconsistent = false; + Star::const_iterator it_inc_simplex = m_stars[idx].begin(); + Star::const_iterator it_inc_simplex_end = m_stars[idx].end(); + for (; it_inc_simplex != it_inc_simplex_end; + ++it_inc_simplex) { + // Skip infinite cells + if (is_infinite(*it_inc_simplex)) + continue; + + Simplex c = *it_inc_simplex; + c.insert(idx); // Add the missing index + + sc.add_simplex(c); + + // If we do not already know this star is inconsistent, test it + if (!is_inconsistent && !is_simplex_consistent(c)) + is_inconsistent = true; + } + + if (is_inconsistent) { + // Export star to OFF file + std::stringstream output_filename; + output_filename << filename_base << "_" << idx << ".off"; + std::ofstream off_stream(output_filename.str().c_str()); + export_to_off(sc, off_stream); + } + } + } + + class Compare_distance_to_ref_point { + public: + Compare_distance_to_ref_point(Point const& ref, K const& k) + : m_ref(ref), m_k(k) { } + + bool operator()(Point const& p1, Point const& p2) { + typename K::Squared_distance_d sqdist = + m_k.squared_distance_d_object(); + return sqdist(p1, m_ref) < sqdist(p2, m_ref); + } + + private: + Point const& m_ref; + K const& m_k; + }; + +#ifdef GUDHI_USE_TBB + // Functor for compute_tangential_complex function + class Compute_tangent_triangulation { + Tangential_complex & m_tc; + + public: + // Constructor + Compute_tangent_triangulation(Tangential_complex &tc) + : m_tc(tc) { } + + // Constructor + Compute_tangent_triangulation(const Compute_tangent_triangulation &ctt) + : m_tc(ctt.m_tc) { } + + // operator() + void operator()(const tbb::blocked_range& r) const { + for (size_t i = r.begin(); i != r.end(); ++i) + m_tc.compute_tangent_triangulation(i); + } + }; + + // Functor for refresh_tangential_complex function + class Refresh_tangent_triangulation { + Tangential_complex & m_tc; + Points_ds const& m_updated_pts_ds; + + public: + // Constructor + Refresh_tangent_triangulation(Tangential_complex &tc, Points_ds const& updated_pts_ds) + : m_tc(tc), m_updated_pts_ds(updated_pts_ds) { } + + // Constructor + Refresh_tangent_triangulation(const Refresh_tangent_triangulation &ctt) + : m_tc(ctt.m_tc), m_updated_pts_ds(ctt.m_updated_pts_ds) { } + + // operator() + void operator()(const tbb::blocked_range& r) const { + for (size_t i = r.begin(); i != r.end(); ++i) + m_tc.refresh_tangent_triangulation(i, m_updated_pts_ds); + } + }; +#endif // GUDHI_USE_TBB + + bool is_infinite(Simplex const& s) const { + return *s.rbegin() == (std::numeric_limits::max)(); + } + + // Output: "triangulation" is a Regular Triangulation containing at least the + // star of "center_pt" + // Returns the handle of the center vertex + Tr_vertex_handle compute_star(std::size_t i, const Point ¢er_pt, const Tangent_space_basis &tsb, + Triangulation &triangulation, bool verbose = false) { + int tangent_space_dim = tsb.dimension(); + const Tr_traits &local_tr_traits = triangulation.geom_traits(); + Tr_vertex_handle center_vertex; + + // Kernel functor & objects + typename K::Squared_distance_d k_sqdist = m_k.squared_distance_d_object(); + + // Triangulation's traits functor & objects + typename Tr_traits::Compute_weight_d point_weight = local_tr_traits.compute_weight_d_object(); + typename Tr_traits::Power_center_d power_center = local_tr_traits.power_center_d_object(); + + //*************************************************** + // Build a minimal triangulation in the tangent space + // (we only need the star of p) + //*************************************************** + + // Insert p + Tr_point proj_wp; + if (i == tsb.origin()) { + // Insert {(0, 0, 0...), m_weights[i]} + proj_wp = local_tr_traits.construct_weighted_point_d_object()(local_tr_traits.construct_point_d_object()(tangent_space_dim, CGAL::ORIGIN), + m_weights[i]); + } else { + const Weighted_point& wp = compute_perturbed_weighted_point(i); + proj_wp = project_point_and_compute_weight(wp, tsb, local_tr_traits); + } + + center_vertex = triangulation.insert(proj_wp); + center_vertex->data() = i; + if (verbose) + std::cerr << "* Inserted point #" << i << "\n"; + +#ifdef GUDHI_TC_VERY_VERBOSE + std::size_t num_attempts_to_insert_points = 1; + std::size_t num_inserted_points = 1; +#endif + // const int NUM_NEIGHBORS = 150; + // KNS_range ins_range = m_points_ds.query_k_nearest_neighbors(center_pt, NUM_NEIGHBORS); + INS_range ins_range = m_points_ds.query_incremental_nearest_neighbors(center_pt); + + // While building the local triangulation, we keep the radius + // of the sphere "star sphere" centered at "center_vertex" + // and which contains all the + // circumspheres of the star of "center_vertex" + boost::optional squared_star_sphere_radius_plus_margin; + + // Insert points until we find a point which is outside "star sphere" + for (auto nn_it = ins_range.begin(); + nn_it != ins_range.end(); + ++nn_it) { + std::size_t neighbor_point_idx = nn_it->first; + + // ith point = p, which is already inserted + if (neighbor_point_idx != i) { + // No need to lock the Mutex_for_perturb here since this will not be + // called while other threads are perturbing the positions + Point neighbor_pt; + FT neighbor_weight; + compute_perturbed_weighted_point(neighbor_point_idx, neighbor_pt, neighbor_weight); + + if (squared_star_sphere_radius_plus_margin && + k_sqdist(center_pt, neighbor_pt) > *squared_star_sphere_radius_plus_margin) + break; + + Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb, + local_tr_traits); + +#ifdef GUDHI_TC_VERY_VERBOSE + ++num_attempts_to_insert_points; +#endif + + + Tr_vertex_handle vh = triangulation.insert_if_in_star(proj_pt, center_vertex); + // Tr_vertex_handle vh = triangulation.insert(proj_pt); + if (vh != Tr_vertex_handle() && vh->data() == (std::numeric_limits::max)()) { +#ifdef GUDHI_TC_VERY_VERBOSE + ++num_inserted_points; +#endif + if (verbose) + std::cerr << "* Inserted point #" << neighbor_point_idx << "\n"; + + vh->data() = neighbor_point_idx; + + // Let's recompute squared_star_sphere_radius_plus_margin + if (triangulation.current_dimension() >= tangent_space_dim) { + squared_star_sphere_radius_plus_margin = boost::none; + // Get the incident cells and look for the biggest circumsphere + std::vector incident_cells; + triangulation.incident_full_cells( + center_vertex, + std::back_inserter(incident_cells)); + for (typename std::vector::iterator cit = + incident_cells.begin(); cit != incident_cells.end(); ++cit) { + Tr_full_cell_handle cell = *cit; + if (triangulation.is_infinite(cell)) { + squared_star_sphere_radius_plus_margin = boost::none; + break; + } else { + // Note that this uses the perturbed point since it uses + // the points of the local triangulation + Tr_point c = power_center(boost::make_transform_iterator(cell->vertices_begin(), + vertex_handle_to_point), + boost::make_transform_iterator(cell->vertices_end(), + vertex_handle_to_point)); + + FT sq_power_sphere_diam = 4 * point_weight(c); + + if (!squared_star_sphere_radius_plus_margin || + sq_power_sphere_diam > *squared_star_sphere_radius_plus_margin) { + squared_star_sphere_radius_plus_margin = sq_power_sphere_diam; + } + } + } + + // Let's add the margin, now + // The value depends on whether we perturb weight or position + if (squared_star_sphere_radius_plus_margin) { + // "2*m_last_max_perturb" because both points can be perturbed + squared_star_sphere_radius_plus_margin = CGAL::square(std::sqrt(*squared_star_sphere_radius_plus_margin) + + 2 * m_last_max_perturb); + + // Save it in `m_squared_star_spheres_radii_incl_margin` + m_squared_star_spheres_radii_incl_margin[i] = + *squared_star_sphere_radius_plus_margin; + } else { + m_squared_star_spheres_radii_incl_margin[i] = FT(-1); + } + } + } + } + } + + return center_vertex; + } + + void refresh_tangent_triangulation(std::size_t i, Points_ds const& updated_pts_ds, bool verbose = false) { + if (verbose) + std::cerr << "** Refreshing tangent tri #" << i << " **\n"; + + if (m_squared_star_spheres_radii_incl_margin[i] == FT(-1)) + return compute_tangent_triangulation(i, verbose); + + Point center_point = compute_perturbed_point(i); + // Among updated point, what is the closer from our center point? + std::size_t closest_pt_index = + updated_pts_ds.query_k_nearest_neighbors(center_point, 1, false).begin()->first; + + typename K::Construct_weighted_point_d k_constr_wp = + m_k.construct_weighted_point_d_object(); + typename K::Power_distance_d k_power_dist = m_k.power_distance_d_object(); + + // Construct a weighted point equivalent to the star sphere + Weighted_point star_sphere = k_constr_wp(compute_perturbed_point(i), + m_squared_star_spheres_radii_incl_margin[i]); + Weighted_point closest_updated_point = + compute_perturbed_weighted_point(closest_pt_index); + + // Is the "closest point" inside our star sphere? + if (k_power_dist(star_sphere, closest_updated_point) <= FT(0)) + compute_tangent_triangulation(i, verbose); + } + + void compute_tangent_triangulation(std::size_t i, bool verbose = false) { + if (verbose) + std::cerr << "** Computing tangent tri #" << i << " **\n"; + // std::cerr << "***********************************************\n"; + + // No need to lock the mutex here since this will not be called while + // other threads are perturbing the positions + const Point center_pt = compute_perturbed_point(i); + Tangent_space_basis &tsb = m_tangent_spaces[i]; + + // Estimate the tangent space + if (!m_are_tangent_spaces_computed[i]) { +#ifdef GUDHI_TC_EXPORT_NORMALS + tsb = compute_tangent_space(center_pt, i, true /*normalize*/, &m_orth_spaces[i]); +#else + tsb = compute_tangent_space(center_pt, i); +#endif + } + +#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) + Gudhi::Clock t; +#endif + int tangent_space_dim = tangent_basis_dim(i); + Triangulation &local_tr = + m_triangulations[i].construct_triangulation(tangent_space_dim); + + m_triangulations[i].center_vertex() = + compute_star(i, center_pt, tsb, local_tr, verbose); + +#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) + t.end(); + std::cerr << " - triangulation construction: " << t.num_seconds() << " s.\n"; + t.reset(); +#endif + +#ifdef GUDHI_TC_VERY_VERBOSE + std::cerr << "Inserted " << num_inserted_points << " points / " + << num_attempts_to_insert_points << " attemps to compute the star\n"; +#endif + + update_star(i); + +#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE) + t.end(); + std::cerr << " - update_star: " << t.num_seconds() << " s.\n"; +#endif + } + + // Updates m_stars[i] directly from m_triangulations[i] + + void update_star(std::size_t i) { + Star &star = m_stars[i]; + star.clear(); + Triangulation &local_tr = m_triangulations[i].tr(); + Tr_vertex_handle center_vertex = m_triangulations[i].center_vertex(); + int cur_dim_plus_1 = local_tr.current_dimension() + 1; + + std::vector incident_cells; + local_tr.incident_full_cells( + center_vertex, std::back_inserter(incident_cells)); + + typename std::vector::const_iterator it_c = incident_cells.begin(); + typename std::vector::const_iterator it_c_end = incident_cells.end(); + // For each cell + for (; it_c != it_c_end; ++it_c) { + // Will contain all indices except center_vertex + Incident_simplex incident_simplex; + for (int j = 0; j < cur_dim_plus_1; ++j) { + std::size_t index = (*it_c)->vertex(j)->data(); + if (index != i) + incident_simplex.insert(index); + } + GUDHI_CHECK(incident_simplex.size() == cur_dim_plus_1 - 1, + std::logic_error("update_star: wrong size of incident simplex")); + star.push_back(incident_simplex); + } + } + + // Estimates tangent subspaces using PCA + + Tangent_space_basis compute_tangent_space(const Point &p + , const std::size_t i + , bool normalize_basis = true + , Orthogonal_space_basis *p_orth_space_basis = NULL + ) { + unsigned int num_pts_for_pca = (std::min)(static_cast (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)), + static_cast (m_points.size())); + + // Kernel functors + typename K::Construct_vector_d constr_vec = + m_k.construct_vector_d_object(); + typename K::Compute_coordinate_d coord = + m_k.compute_coordinate_d_object(); + +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + KNS_range kns_range = m_points_ds_for_tse.query_k_nearest_neighbors( + p, num_pts_for_pca, false); + const Points &points_for_pca = m_points_for_tse; +#else + KNS_range kns_range = m_points_ds.query_k_nearest_neighbors(p, num_pts_for_pca, false); + const Points &points_for_pca = m_points; +#endif + + // One row = one point + Eigen::MatrixXd mat_points(num_pts_for_pca, m_ambient_dim); + auto nn_it = kns_range.begin(); + for (unsigned int j = 0; + j < num_pts_for_pca && nn_it != kns_range.end(); + ++j, ++nn_it) { + for (int i = 0; i < m_ambient_dim; ++i) { + mat_points(j, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i)); + } + } + Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean(); + Eigen::MatrixXd cov = centered.adjoint() * centered; + Eigen::SelfAdjointEigenSolver eig(cov); + + Tangent_space_basis tsb(i); // p = compute_perturbed_point(i) here + + // The eigenvectors are sorted in increasing order of their corresponding + // eigenvalues + for (int j = m_ambient_dim - 1; + j >= m_ambient_dim - m_intrinsic_dim; + --j) { + if (normalize_basis) { + Vector v = constr_vec(m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim); + tsb.push_back(normalize_vector(v, m_k)); + } else { + tsb.push_back(constr_vec( + m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim)); + } + } + + if (p_orth_space_basis) { + p_orth_space_basis->set_origin(i); + for (int j = m_ambient_dim - m_intrinsic_dim - 1; + j >= 0; + --j) { + if (normalize_basis) { + Vector v = constr_vec(m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim); + p_orth_space_basis->push_back(normalize_vector(v, m_k)); + } else { + p_orth_space_basis->push_back(constr_vec( + m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim)); + } + } + } + + m_are_tangent_spaces_computed[i] = true; + + return tsb; + } + + // Compute the space tangent to a simplex (p1, p2, ... pn) + // TODO(CJ): Improve this? + // Basically, it takes all the neighbor points to p1, p2... pn and runs PCA + // on it. Note that most points are duplicated. + + Tangent_space_basis compute_tangent_space(const Simplex &s, bool normalize_basis = true) { + unsigned int num_pts_for_pca = (std::min)(static_cast (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)), + static_cast (m_points.size())); + + // Kernel functors + typename K::Construct_vector_d constr_vec = + m_k.construct_vector_d_object(); + typename K::Compute_coordinate_d coord = + m_k.compute_coordinate_d_object(); + typename K::Squared_length_d sqlen = + m_k.squared_length_d_object(); + typename K::Scaled_vector_d scaled_vec = + m_k.scaled_vector_d_object(); + typename K::Scalar_product_d scalar_pdct = + m_k.scalar_product_d_object(); + typename K::Difference_of_vectors_d diff_vec = + m_k.difference_of_vectors_d_object(); + + // One row = one point + Eigen::MatrixXd mat_points(s.size() * num_pts_for_pca, m_ambient_dim); + unsigned int current_row = 0; + + for (Simplex::const_iterator it_index = s.begin(); + it_index != s.end(); ++it_index) { + const Point &p = m_points[*it_index]; + +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + KNS_range kns_range = m_points_ds_for_tse.query_k_nearest_neighbors( + p, num_pts_for_pca, false); + const Points &points_for_pca = m_points_for_tse; +#else + KNS_range kns_range = m_points_ds.query_k_nearest_neighbors(p, num_pts_for_pca, false); + const Points &points_for_pca = m_points; +#endif + + auto nn_it = kns_range.begin(); + for (; + current_row < num_pts_for_pca && nn_it != kns_range.end(); + ++current_row, ++nn_it) { + for (int i = 0; i < m_ambient_dim; ++i) { + mat_points(current_row, i) = + CGAL::to_double(coord(points_for_pca[nn_it->first], i)); + } + } + } + Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean(); + Eigen::MatrixXd cov = centered.adjoint() * centered; + Eigen::SelfAdjointEigenSolver eig(cov); + + Tangent_space_basis tsb; + + // The eigenvectors are sorted in increasing order of their corresponding + // eigenvalues + for (int j = m_ambient_dim - 1; + j >= m_ambient_dim - m_intrinsic_dim; + --j) { + if (normalize_basis) { + Vector v = constr_vec(m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim); + tsb.push_back(normalize_vector(v, m_k)); + } else { + tsb.push_back(constr_vec( + m_ambient_dim, + eig.eigenvectors().col(j).data(), + eig.eigenvectors().col(j).data() + m_ambient_dim)); + } + } + + return tsb; + } + + // Returns the dimension of the ith local triangulation + + int tangent_basis_dim(std::size_t i) const { + return m_tangent_spaces[i].dimension(); + } + + Point compute_perturbed_point(std::size_t pt_idx) const { +#ifdef GUDHI_TC_PERTURB_POSITION + return m_k.translated_point_d_object()( + m_points[pt_idx], m_translations[pt_idx]); +#else + return m_points[pt_idx]; +#endif + } + + void compute_perturbed_weighted_point(std::size_t pt_idx, Point &p, FT &w) const { +#ifdef GUDHI_TC_PERTURB_POSITION + p = m_k.translated_point_d_object()( + m_points[pt_idx], m_translations[pt_idx]); +#else + p = m_points[pt_idx]; +#endif + w = m_weights[pt_idx]; + } + + Weighted_point compute_perturbed_weighted_point(std::size_t pt_idx) const { + typename K::Construct_weighted_point_d k_constr_wp = + m_k.construct_weighted_point_d_object(); + + Weighted_point wp = k_constr_wp( +#ifdef GUDHI_TC_PERTURB_POSITION + m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]), +#else + m_points[pt_idx], +#endif + m_weights[pt_idx]); + + return wp; + } + + Point unproject_point(const Tr_point &p, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + typename K::Translated_point_d k_transl = + m_k.translated_point_d_object(); + typename K::Scaled_vector_d k_scaled_vec = + m_k.scaled_vector_d_object(); + typename Tr_traits::Compute_coordinate_d coord = + tr_traits.compute_coordinate_d_object(); + + Point global_point = compute_perturbed_point(tsb.origin()); + for (int i = 0; i < m_intrinsic_dim; ++i) + global_point = k_transl(global_point, + k_scaled_vec(tsb[i], coord(p, i))); + + return global_point; + } + + // Project the point in the tangent space + // Resulting point coords are expressed in tsb's space + Tr_bare_point project_point(const Point &p, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + typename K::Scalar_product_d scalar_pdct = + m_k.scalar_product_d_object(); + typename K::Difference_of_points_d diff_points = + m_k.difference_of_points_d_object(); + + Vector v = diff_points(p, compute_perturbed_point(tsb.origin())); + + std::vector coords; + // Ambiant-space coords of the projected point + coords.reserve(tsb.dimension()); + for (std::size_t i = 0; i < m_intrinsic_dim; ++i) { + // Local coords are given by the scalar product with the vectors of tsb + FT coord = scalar_pdct(v, tsb[i]); + coords.push_back(coord); + } + + return tr_traits.construct_point_d_object()( + static_cast (coords.size()), coords.begin(), coords.end()); + } + + // Project the point in the tangent space + // The weight will be the squared distance between p and the projection of p + // Resulting point coords are expressed in tsb's space + + Tr_point project_point_and_compute_weight(const Weighted_point &wp, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + typename K::Point_drop_weight_d k_drop_w = + m_k.point_drop_weight_d_object(); + typename K::Compute_weight_d k_point_weight = + m_k.compute_weight_d_object(); + return project_point_and_compute_weight( + k_drop_w(wp), k_point_weight(wp), tsb, tr_traits); + } + + // Same as above, with slightly different parameters + Tr_point project_point_and_compute_weight(const Point &p, const FT w, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + const int point_dim = m_k.point_dimension_d_object()(p); + + typename K::Construct_point_d constr_pt = + m_k.construct_point_d_object(); + typename K::Scalar_product_d scalar_pdct = + m_k.scalar_product_d_object(); + typename K::Difference_of_points_d diff_points = + m_k.difference_of_points_d_object(); + typename K::Compute_coordinate_d coord = + m_k.compute_coordinate_d_object(); + typename K::Construct_cartesian_const_iterator_d ccci = + m_k.construct_cartesian_const_iterator_d_object(); + + Point origin = compute_perturbed_point(tsb.origin()); + Vector v = diff_points(p, origin); + + // Same dimension? Then the weight is 0 + bool same_dim = (point_dim == tsb.dimension()); + + std::vector coords; + // Ambiant-space coords of the projected point + std::vector p_proj(ccci(origin), ccci(origin, 0)); + coords.reserve(tsb.dimension()); + for (int i = 0; i < tsb.dimension(); ++i) { + // Local coords are given by the scalar product with the vectors of tsb + FT c = scalar_pdct(v, tsb[i]); + coords.push_back(c); + + // p_proj += c * tsb[i] + if (!same_dim) { + for (int j = 0; j < point_dim; ++j) + p_proj[j] += c * coord(tsb[i], j); + } + } + + // Same dimension? Then the weight is 0 + FT sq_dist_to_proj_pt = 0; + if (!same_dim) { + Point projected_pt = constr_pt(point_dim, p_proj.begin(), p_proj.end()); + sq_dist_to_proj_pt = m_k.squared_distance_d_object()(p, projected_pt); + } + + return tr_traits.construct_weighted_point_d_object() + (tr_traits.construct_point_d_object()(static_cast (coords.size()), coords.begin(), coords.end()), + w - sq_dist_to_proj_pt); + } + + // Project all the points in the tangent space + + template + std::vector project_points_and_compute_weights( + const Indexed_point_range &point_indices, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + std::vector ret; + for (typename Indexed_point_range::const_iterator + it = point_indices.begin(), it_end = point_indices.end(); + it != it_end; ++it) { + ret.push_back(project_point_and_compute_weight( + compute_perturbed_weighted_point(*it), tsb, tr_traits)); + } + return ret; + } + + // A simplex here is a local tri's full cell handle + + bool is_simplex_consistent(Tr_full_cell_handle fch, int cur_dim) const { + Simplex c; + for (int i = 0; i < cur_dim + 1; ++i) { + std::size_t data = fch->vertex(i)->data(); + c.insert(data); + } + return is_simplex_consistent(c); + } + + // A simplex here is a list of point indices + // TODO(CJ): improve it like the other "is_simplex_consistent" below + + bool is_simplex_consistent(Simplex const& simplex) const { + // Check if the simplex is in the stars of all its vertices + Simplex::const_iterator it_point_idx = simplex.begin(); + // For each point p of the simplex, we parse the incidents cells of p + // and we check if "simplex" is among them + for (; it_point_idx != simplex.end(); ++it_point_idx) { + std::size_t point_idx = *it_point_idx; + // Don't check infinite simplices + if (point_idx == (std::numeric_limits::max)()) + continue; + + Star const& star = m_stars[point_idx]; + + // What we're looking for is "simplex" \ point_idx + Incident_simplex is_to_find = simplex; + is_to_find.erase(point_idx); + + // For each cell + if (std::find(star.begin(), star.end(), is_to_find) == star.end()) + return false; + } + + return true; + } + + // A simplex here is a list of point indices + // "s" contains all the points of the simplex except "center_point" + // This function returns the points whose star doesn't contain the simplex + // N.B.: the function assumes that the simplex is contained in + // star(center_point) + + template // value_type = std::size_t + bool is_simplex_consistent( + std::size_t center_point, + Incident_simplex const& s, // without "center_point" + OutputIterator points_whose_star_does_not_contain_s, + bool check_also_in_non_maximal_faces = false) const { + Simplex full_simplex = s; + full_simplex.insert(center_point); + + // Check if the simplex is in the stars of all its vertices + Incident_simplex::const_iterator it_point_idx = s.begin(); + // For each point p of the simplex, we parse the incidents cells of p + // and we check if "simplex" is among them + for (; it_point_idx != s.end(); ++it_point_idx) { + std::size_t point_idx = *it_point_idx; + // Don't check infinite simplices + if (point_idx == (std::numeric_limits::max)()) + continue; + + Star const& star = m_stars[point_idx]; + + // What we're looking for is full_simplex \ point_idx + Incident_simplex is_to_find = full_simplex; + is_to_find.erase(point_idx); + + if (check_also_in_non_maximal_faces) { + // For each simplex "is" of the star, check if ic_to_simplex is + // included in "is" + bool found = false; + for (Star::const_iterator is = star.begin(), is_end = star.end(); + !found && is != is_end; ++is) { + if (std::includes(is->begin(), is->end(), + is_to_find.begin(), is_to_find.end())) + found = true; + } + + if (!found) + *points_whose_star_does_not_contain_s++ = point_idx; + } else { + // Does the star contain is_to_find? + if (std::find(star.begin(), star.end(), is_to_find) == star.end()) + *points_whose_star_does_not_contain_s++ = point_idx; + } + } + + return true; + } + + // A simplex here is a list of point indices + // It looks for s in star(p). + // "s" contains all the points of the simplex except p. + bool is_simplex_in_star(std::size_t p, + Incident_simplex const& s, + bool check_also_in_non_maximal_faces = true) const { + Star const& star = m_stars[p]; + + if (check_also_in_non_maximal_faces) { + // For each simplex "is" of the star, check if ic_to_simplex is + // included in "is" + bool found = false; + for (Star::const_iterator is = star.begin(), is_end = star.end(); + !found && is != is_end; ++is) { + if (std::includes(is->begin(), is->end(), s.begin(), s.end())) + found = true; + } + + return found; + } else { + return !(std::find(star.begin(), star.end(), s) == star.end()); + } + } + +#ifdef GUDHI_USE_TBB + // Functor for try_to_solve_inconsistencies_in_a_local_triangulation function + class Try_to_solve_inconsistencies_in_a_local_triangulation { + Tangential_complex & m_tc; + double m_max_perturb; + tbb::combinable &m_num_inconsistencies; + tbb::combinable > &m_updated_points; + + public: + // Constructor + Try_to_solve_inconsistencies_in_a_local_triangulation(Tangential_complex &tc, + double max_perturb, + tbb::combinable &num_inconsistencies, + tbb::combinable > &updated_points) + : m_tc(tc), + m_max_perturb(max_perturb), + m_num_inconsistencies(num_inconsistencies), + m_updated_points(updated_points) { } + + // Constructor + Try_to_solve_inconsistencies_in_a_local_triangulation(const Try_to_solve_inconsistencies_in_a_local_triangulation& + tsilt) + : m_tc(tsilt.m_tc), + m_max_perturb(tsilt.m_max_perturb), + m_num_inconsistencies(tsilt.m_num_inconsistencies), + m_updated_points(tsilt.m_updated_points) { } + + // operator() + void operator()(const tbb::blocked_range& r) const { + for (size_t i = r.begin(); i != r.end(); ++i) { + m_num_inconsistencies.local() += + m_tc.try_to_solve_inconsistencies_in_a_local_triangulation(i, m_max_perturb, + std::back_inserter(m_updated_points.local())); + } + } + }; +#endif // GUDHI_USE_TBB + + void perturb(std::size_t point_idx, double max_perturb) { + const Tr_traits &local_tr_traits = + m_triangulations[point_idx].tr().geom_traits(); + typename Tr_traits::Compute_coordinate_d coord = + local_tr_traits.compute_coordinate_d_object(); + typename K::Translated_point_d k_transl = + m_k.translated_point_d_object(); + typename K::Construct_vector_d k_constr_vec = + m_k.construct_vector_d_object(); + typename K::Scaled_vector_d k_scaled_vec = + m_k.scaled_vector_d_object(); + + CGAL::Random_points_in_ball_d + tr_point_in_ball_generator(m_intrinsic_dim, + m_random_generator.get_double(0., max_perturb)); + + Tr_point local_random_transl = + local_tr_traits.construct_weighted_point_d_object()(*tr_point_in_ball_generator++, 0); + Translation_for_perturb global_transl = k_constr_vec(m_ambient_dim); + const Tangent_space_basis &tsb = m_tangent_spaces[point_idx]; + for (int i = 0; i < m_intrinsic_dim; ++i) { + global_transl = k_transl(global_transl, + k_scaled_vec(tsb[i], coord(local_random_transl, i))); + } + // Parallel +#if defined(GUDHI_USE_TBB) + m_p_perturb_mutexes[point_idx].lock(); + m_translations[point_idx] = global_transl; + m_p_perturb_mutexes[point_idx].unlock(); + // Sequential +#else + m_translations[point_idx] = global_transl; +#endif + } + + // Return true if inconsistencies were found + template + bool try_to_solve_inconsistencies_in_a_local_triangulation(std::size_t tr_index, + double max_perturb, + OutputIt perturbed_pts_indices = CGAL::Emptyset_iterator()) { + bool is_inconsistent = false; + + Star const& star = m_stars[tr_index]; + Tr_vertex_handle center_vh = m_triangulations[tr_index].center_vertex(); + + // For each incident simplex + Star::const_iterator it_inc_simplex = star.begin(); + Star::const_iterator it_inc_simplex_end = star.end(); + for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) { + const Incident_simplex &incident_simplex = *it_inc_simplex; + + // Don't check infinite cells + if (is_infinite(incident_simplex)) + continue; + + Simplex c = incident_simplex; + c.insert(tr_index); // Add the missing index + + // Perturb the center point + if (!is_simplex_consistent(c)) { + is_inconsistent = true; + + std::size_t idx = tr_index; + + perturb(tr_index, max_perturb); + *perturbed_pts_indices++ = idx; + + // We will try the other cells next time + break; + } + } + + return is_inconsistent; + } + + + // 1st line: number of points + // Then one point per line + std::ostream &export_point_set(std::ostream & os, + bool use_perturbed_points = false, + const char *coord_separator = " ") const { + if (use_perturbed_points) { + std::vector perturbed_points; + perturbed_points.reserve(m_points.size()); + for (std::size_t i = 0; i < m_points.size(); ++i) + perturbed_points.push_back(compute_perturbed_point(i)); + + return export_point_set( + m_k, perturbed_points, os, coord_separator); + } else { + return export_point_set( + m_k, m_points, os, coord_separator); + } + } + + template > + std::ostream &export_vertices_to_off( + std::ostream & os, std::size_t &num_vertices, + bool use_perturbed_points = false, + ProjectionFunctor const& point_projection = ProjectionFunctor()) const { + if (m_points.empty()) { + num_vertices = 0; + return os; + } + + // If m_intrinsic_dim = 1, we output each point two times + // to be able to export each segment as a flat triangle with 3 different + // indices (otherwise, Meshlab detects degenerated simplices) + const int N = (m_intrinsic_dim == 1 ? 2 : 1); + + // Kernel functors + typename K::Compute_coordinate_d coord = + m_k.compute_coordinate_d_object(); + +#ifdef GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF + int num_coords = m_ambient_dim; +#else + int num_coords = (std::min)(m_ambient_dim, 3); +#endif + +#ifdef GUDHI_TC_EXPORT_NORMALS + OS_container::const_iterator it_os = m_orth_spaces.begin(); +#endif + typename Points::const_iterator it_p = m_points.begin(); + typename Points::const_iterator it_p_end = m_points.end(); + // For each point p + for (std::size_t i = 0; it_p != it_p_end; ++it_p, ++i) { + Point p = point_projection( + use_perturbed_points ? compute_perturbed_point(i) : *it_p); + for (int ii = 0; ii < N; ++ii) { + int j = 0; + for (; j < num_coords; ++j) + os << CGAL::to_double(coord(p, j)) << " "; + if (j == 2) + os << "0"; + +#ifdef GUDHI_TC_EXPORT_NORMALS + for (j = 0; j < num_coords; ++j) + os << " " << CGAL::to_double(coord(*it_os->begin(), j)); +#endif + os << "\n"; + } +#ifdef GUDHI_TC_EXPORT_NORMALS + ++it_os; +#endif + } + + num_vertices = N * m_points.size(); + return os; + } + + std::ostream &export_simplices_to_off(std::ostream & os, std::size_t &num_OFF_simplices, + bool color_inconsistencies = false, + Simplex_set const *p_simpl_to_color_in_red = NULL, + Simplex_set const *p_simpl_to_color_in_green = NULL, + Simplex_set const *p_simpl_to_color_in_blue = NULL) + const { + // If m_intrinsic_dim = 1, each point is output two times + // (see export_vertices_to_off) + num_OFF_simplices = 0; + std::size_t num_maximal_simplices = 0; + std::size_t num_inconsistent_maximal_simplices = 0; + std::size_t num_inconsistent_stars = 0; + typename Tr_container::const_iterator it_tr = m_triangulations.begin(); + typename Tr_container::const_iterator it_tr_end = m_triangulations.end(); + // For each triangulation + for (std::size_t idx = 0; it_tr != it_tr_end; ++it_tr, ++idx) { + bool is_star_inconsistent = false; + + Triangulation const& tr = it_tr->tr(); + Tr_vertex_handle center_vh = it_tr->center_vertex(); + + if (tr.current_dimension() < m_intrinsic_dim) + continue; + + // Color for this star + std::stringstream color; + // color << rand()%256 << " " << 100+rand()%156 << " " << 100+rand()%156; + color << 128 << " " << 128 << " " << 128; + + // Gather the triangles here, with an int telling its color + typedef std::vector > Star_using_triangles; + Star_using_triangles star_using_triangles; + + // For each cell of the star + Star::const_iterator it_inc_simplex = m_stars[idx].begin(); + Star::const_iterator it_inc_simplex_end = m_stars[idx].end(); + for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) { + Simplex c = *it_inc_simplex; + c.insert(idx); + std::size_t num_vertices = c.size(); + ++num_maximal_simplices; + + int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue + if (color_inconsistencies && !is_simplex_consistent(c)) { + ++num_inconsistent_maximal_simplices; + color_simplex = 0; + is_star_inconsistent = true; + } else { + if (p_simpl_to_color_in_red && + std::find( + p_simpl_to_color_in_red->begin(), + p_simpl_to_color_in_red->end(), + c) != p_simpl_to_color_in_red->end()) { + color_simplex = 1; + } else if (p_simpl_to_color_in_green && + std::find( + p_simpl_to_color_in_green->begin(), + p_simpl_to_color_in_green->end(), + c) != p_simpl_to_color_in_green->end()) { + color_simplex = 2; + } else if (p_simpl_to_color_in_blue && + std::find( + p_simpl_to_color_in_blue->begin(), + p_simpl_to_color_in_blue->end(), + c) != p_simpl_to_color_in_blue->end()) { + color_simplex = 3; + } + } + + // If m_intrinsic_dim = 1, each point is output two times, + // so we need to multiply each index by 2 + // And if only 2 vertices, add a third one (each vertex is duplicated in + // the file when m_intrinsic dim = 2) + if (m_intrinsic_dim == 1) { + Simplex tmp_c; + Simplex::iterator it = c.begin(); + for (; it != c.end(); ++it) + tmp_c.insert(*it * 2); + if (num_vertices == 2) + tmp_c.insert(*tmp_c.rbegin() + 1); + + c = tmp_c; + } + + if (num_vertices <= 3) { + star_using_triangles.push_back(std::make_pair(c, color_simplex)); + } else { + // num_vertices >= 4: decompose the simplex in triangles + std::vector booleans(num_vertices, false); + std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true); + do { + Simplex triangle; + Simplex::iterator it = c.begin(); + for (int i = 0; it != c.end(); ++i, ++it) { + if (booleans[i]) + triangle.insert(*it); + } + star_using_triangles.push_back( + std::make_pair(triangle, color_simplex)); + } while (std::next_permutation(booleans.begin(), booleans.end())); + } + } + + // For each cell + Star_using_triangles::const_iterator it_simplex = + star_using_triangles.begin(); + Star_using_triangles::const_iterator it_simplex_end = + star_using_triangles.end(); + for (; it_simplex != it_simplex_end; ++it_simplex) { + const Simplex &c = it_simplex->first; + + // Don't export infinite cells + if (is_infinite(c)) + continue; + + int color_simplex = it_simplex->second; + + std::stringstream sstr_c; + + Simplex::const_iterator it_point_idx = c.begin(); + for (; it_point_idx != c.end(); ++it_point_idx) { + sstr_c << *it_point_idx << " "; + } + + os << 3 << " " << sstr_c.str(); + if (color_inconsistencies || p_simpl_to_color_in_red + || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) { + switch (color_simplex) { + case 0: os << " 255 255 0"; + break; + case 1: os << " 255 0 0"; + break; + case 2: os << " 0 255 0"; + break; + case 3: os << " 0 0 255"; + break; + default: os << " " << color.str(); + break; + } + } + ++num_OFF_simplices; + os << "\n"; + } + if (is_star_inconsistent) + ++num_inconsistent_stars; + } + +#ifdef DEBUG_TRACES + std::cerr + << "\n==========================================================\n" + << "Export from list of stars to OFF:\n" + << " * Number of vertices: " << m_points.size() << "\n" + << " * Total number of maximal simplices: " << num_maximal_simplices + << "\n"; + if (color_inconsistencies) { + std::cerr + << " * Number of inconsistent stars: " + << num_inconsistent_stars << " (" + << (m_points.size() > 0 ? + 100. * num_inconsistent_stars / m_points.size() : 0.) << "%)\n" + << " * Number of inconsistent maximal simplices: " + << num_inconsistent_maximal_simplices << " (" + << (num_maximal_simplices > 0 ? + 100. * num_inconsistent_maximal_simplices / num_maximal_simplices + : 0.) << "%)\n"; + } + std::cerr << "==========================================================\n"; +#endif + + return os; + } + + public: + std::ostream &export_simplices_to_off( + const Simplicial_complex &complex, + std::ostream & os, std::size_t &num_OFF_simplices, + Simplex_set const *p_simpl_to_color_in_red = NULL, + Simplex_set const *p_simpl_to_color_in_green = NULL, + Simplex_set const *p_simpl_to_color_in_blue = NULL) + const { + typedef Simplicial_complex::Simplex Simplex; + typedef Simplicial_complex::Simplex_set Simplex_set; + + // If m_intrinsic_dim = 1, each point is output two times + // (see export_vertices_to_off) + num_OFF_simplices = 0; + std::size_t num_maximal_simplices = 0; + + typename Simplex_set::const_iterator it_s = + complex.simplex_range().begin(); + typename Simplex_set::const_iterator it_s_end = + complex.simplex_range().end(); + // For each simplex + for (; it_s != it_s_end; ++it_s) { + Simplex c = *it_s; + ++num_maximal_simplices; + + int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue + if (p_simpl_to_color_in_red && + std::find( + p_simpl_to_color_in_red->begin(), + p_simpl_to_color_in_red->end(), + c) != p_simpl_to_color_in_red->end()) { + color_simplex = 1; + } else if (p_simpl_to_color_in_green && + std::find(p_simpl_to_color_in_green->begin(), + p_simpl_to_color_in_green->end(), + c) != p_simpl_to_color_in_green->end()) { + color_simplex = 2; + } else if (p_simpl_to_color_in_blue && + std::find(p_simpl_to_color_in_blue->begin(), + p_simpl_to_color_in_blue->end(), + c) != p_simpl_to_color_in_blue->end()) { + color_simplex = 3; + } + + // Gather the triangles here + typedef std::vector Triangles; + Triangles triangles; + + int num_vertices = static_cast(c.size()); + // Do not export smaller dimension simplices + if (num_vertices < m_intrinsic_dim + 1) + continue; + + // If m_intrinsic_dim = 1, each point is output two times, + // so we need to multiply each index by 2 + // And if only 2 vertices, add a third one (each vertex is duplicated in + // the file when m_intrinsic dim = 2) + if (m_intrinsic_dim == 1) { + Simplex tmp_c; + Simplex::iterator it = c.begin(); + for (; it != c.end(); ++it) + tmp_c.insert(*it * 2); + if (num_vertices == 2) + tmp_c.insert(*tmp_c.rbegin() + 1); + + c = tmp_c; + } + + if (num_vertices <= 3) { + triangles.push_back(c); + } else { + // num_vertices >= 4: decompose the simplex in triangles + std::vector booleans(num_vertices, false); + std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true); + do { + Simplex triangle; + Simplex::iterator it = c.begin(); + for (int i = 0; it != c.end(); ++i, ++it) { + if (booleans[i]) + triangle.insert(*it); + } + triangles.push_back(triangle); + } while (std::next_permutation(booleans.begin(), booleans.end())); + } + + // For each cell + Triangles::const_iterator it_tri = triangles.begin(); + Triangles::const_iterator it_tri_end = triangles.end(); + for (; it_tri != it_tri_end; ++it_tri) { + // Don't export infinite cells + if (is_infinite(*it_tri)) + continue; + + os << 3 << " "; + Simplex::const_iterator it_point_idx = it_tri->begin(); + for (; it_point_idx != it_tri->end(); ++it_point_idx) { + os << *it_point_idx << " "; + } + + if (p_simpl_to_color_in_red || p_simpl_to_color_in_green + || p_simpl_to_color_in_blue) { + switch (color_simplex) { + case 0: os << " 255 255 0"; + break; + case 1: os << " 255 0 0"; + break; + case 2: os << " 0 255 0"; + break; + case 3: os << " 0 0 255"; + break; + default: os << " 128 128 128"; + break; + } + } + + ++num_OFF_simplices; + os << "\n"; + } + } + +#ifdef DEBUG_TRACES + std::cerr + << "\n==========================================================\n" + << "Export from complex to OFF:\n" + << " * Number of vertices: " << m_points.size() << "\n" + << " * Total number of maximal simplices: " << num_maximal_simplices + << "\n" + << "==========================================================\n"; +#endif + + return os; + } + + private: + const K m_k; + const int m_intrinsic_dim; + const int m_ambient_dim; + + Points m_points; + Weights m_weights; +#ifdef GUDHI_TC_PERTURB_POSITION + Translations_for_perturb m_translations; +#if defined(GUDHI_USE_TBB) + Mutex_for_perturb *m_p_perturb_mutexes; +#endif +#endif + + Points_ds m_points_ds; + double m_last_max_perturb; + std::vector m_are_tangent_spaces_computed; + TS_container m_tangent_spaces; +#ifdef GUDHI_TC_EXPORT_NORMALS + OS_container m_orth_spaces; +#endif + Tr_container m_triangulations; // Contains the triangulations + // and their center vertex + Stars_container m_stars; + std::vector m_squared_star_spheres_radii_incl_margin; + +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + Points m_points_for_tse; + Points_ds m_points_ds_for_tse; +#endif + + mutable CGAL::Random m_random_generator; +}; // /class Tangential_complex + +} // end namespace tangential_complex +} // end namespace Gudhi + +#endif // TANGENTIAL_COMPLEX_H_ diff --git a/include/gudhi/Tangential_complex/Simplicial_complex.h b/include/gudhi/Tangential_complex/Simplicial_complex.h new file mode 100644 index 00000000..65c74ca5 --- /dev/null +++ b/include/gudhi/Tangential_complex/Simplicial_complex.h @@ -0,0 +1,539 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_ +#define TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_ + +#include +#include +#include +#include + +#include + +// For is_pure_pseudomanifold +#include +#include +#include +#include + +#include +#include +#include +#include // for map<> +#include // for vector<> +#include // for set<> + +namespace Gudhi { +namespace tangential_complex { +namespace internal { + +class Simplicial_complex { + public: + typedef boost::container::flat_set Simplex; + typedef std::set Simplex_set; + + // If perform_checks = true, the function: + // - won't insert the simplex if it is already in a higher dim simplex + // - will erase any lower-dim simplices that are faces of the new simplex + // Returns true if the simplex was added + bool add_simplex( + const Simplex &s, bool perform_checks = true) { + if (perform_checks) { + unsigned int num_pts = static_cast (s.size()); + std::vector to_erase; + bool check_higher_dim_simpl = true; + for (Complex::iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + // Check if the simplex is not already in a higher dim simplex + if (check_higher_dim_simpl + && it_simplex->size() > num_pts + && std::includes(it_simplex->begin(), it_simplex->end(), + s.begin(), s.end())) { + // No need to insert it, then + return false; + } + // Check if the simplex includes some lower-dim simplices + if (it_simplex->size() < num_pts + && std::includes(s.begin(), s.end(), + it_simplex->begin(), it_simplex->end())) { + to_erase.push_back(it_simplex); + // We don't need to check higher-sim simplices any more + check_higher_dim_simpl = false; + } + } + for (std::vector::const_iterator it = to_erase.begin(); + it != to_erase.end(); ++it) { + m_complex.erase(*it); + } + } + return m_complex.insert(s).second; + } + + const Simplex_set &simplex_range() const { + return m_complex; + } + + bool empty() { + return m_complex.empty(); + } + + void clear() { + m_complex.clear(); + } + + template + void get_simplices_matching_test(Test test, Output_it out) { + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + if (test(*it_simplex)) + *out++ = *it_simplex; + } + } + + // When a simplex S has only one co-face C, we can remove S and C + // without changing the topology + + void collapse(int max_simplex_dim, bool quiet = false) { +#ifdef DEBUG_TRACES + if (!quiet) + std::cerr << "Collapsing... "; +#endif + // We note k = max_simplex_dim - 1 + int k = max_simplex_dim - 1; + + typedef Complex::iterator Simplex_iterator; + typedef std::vector Simplex_iterator_list; + typedef std::map Cofaces_map; + + std::size_t num_collapsed_maximal_simplices = 0; + do { + num_collapsed_maximal_simplices = 0; + // Create a map associating each non-maximal k-faces to the list of its + // maximal cofaces + Cofaces_map cofaces_map; + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + if (static_cast (it_simplex->size()) > k + 1) { + std::vector k_faces; + // Get the k-faces composing the simplex + combinations(*it_simplex, k + 1, std::back_inserter(k_faces)); + for (const auto &comb : k_faces) + cofaces_map[comb].push_back(it_simplex); + } + } + + // For each non-maximal k-face F, if F has only one maximal coface Cf: + // - Look for the other k-faces F2, F3... of Cf in the map and: + // * if the list contains only Cf, clear the list (we don't remove the + // list since it creates troubles with the iterators) and add the F2, + // F3... to the complex + // * otherwise, remove Cf from the associated list + // - Remove Cf from the complex + for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(), + it_map_end = cofaces_map.end(); + it_map_elt != it_map_end; + ++it_map_elt) { + if (it_map_elt->second.size() == 1) { + std::vector k_faces; + const Simplex_iterator_list::value_type &it_Cf = + *it_map_elt->second.begin(); + GUDHI_CHECK(it_Cf->size() == max_simplex_dim + 1, + std::logic_error("Wrong dimension")); + // Get the k-faces composing the simplex + combinations(*it_Cf, k + 1, std::back_inserter(k_faces)); + for (const auto &f2 : k_faces) { + // Skip F + if (f2 != it_map_elt->first) { + Cofaces_map::iterator it_comb_in_map = cofaces_map.find(f2); + if (it_comb_in_map->second.size() == 1) { + it_comb_in_map->second.clear(); + m_complex.insert(f2); + } else { // it_comb_in_map->second.size() > 1 + Simplex_iterator_list::iterator it = std::find(it_comb_in_map->second.begin(), + it_comb_in_map->second.end(), + it_Cf); + GUDHI_CHECK(it != it_comb_in_map->second.end(), + std::logic_error("Error: it == it_comb_in_map->second.end()")); + it_comb_in_map->second.erase(it); + } + } + } + m_complex.erase(it_Cf); + ++num_collapsed_maximal_simplices; + } + } + // Repeat until no maximal simplex got removed + } while (num_collapsed_maximal_simplices > 0); + + // Collapse the lower dimension simplices + if (k > 0) + collapse(max_simplex_dim - 1, true); + +#ifdef DEBUG_TRACES + if (!quiet) + std::cerr << "done.\n"; +#endif + } + + void display_stats() const { + std::cerr << yellow << "Complex stats:\n" << white; + + if (m_complex.empty()) { + std::cerr << " * No simplices.\n"; + } else { + // Number of simplex for each dimension + std::map simplex_stats; + + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + ++simplex_stats[static_cast (it_simplex->size()) - 1]; + } + + for (std::map::const_iterator it_map = simplex_stats.begin(); + it_map != simplex_stats.end(); ++it_map) { + std::cerr << " * " << it_map->first << "-simplices: " + << it_map->second << "\n"; + } + } + } + + // verbose_level = 0, 1 or 2 + bool is_pure_pseudomanifold__do_not_check_if_stars_are_connected(int simplex_dim, + bool allow_borders = false, + bool exit_at_the_first_problem = false, + int verbose_level = 0, + std::size_t *p_num_wrong_dim_simplices = NULL, + std::size_t *p_num_wrong_number_of_cofaces = NULL) const { + typedef Simplex K_1_face; + typedef std::map Cofaces_map; + + std::size_t num_wrong_dim_simplices = 0; + std::size_t num_wrong_number_of_cofaces = 0; + + // Counts the number of cofaces of each K_1_face + + // Create a map associating each non-maximal k-faces to the list of its + // maximal cofaces + Cofaces_map cofaces_map; + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + if (static_cast (it_simplex->size()) != simplex_dim + 1) { + if (verbose_level >= 2) + std::cerr << "Found a simplex with dim = " + << it_simplex->size() - 1 << "\n"; + ++num_wrong_dim_simplices; + } else { + std::vector k_1_faces; + // Get the facets composing the simplex + combinations( + *it_simplex, simplex_dim, std::back_inserter(k_1_faces)); + for (const auto &k_1_face : k_1_faces) { + ++cofaces_map[k_1_face]; + } + } + } + + for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(), + it_map_end = cofaces_map.end(); + it_map_elt != it_map_end; + ++it_map_elt) { + if (it_map_elt->second != 2 + && (!allow_borders || it_map_elt->second != 1)) { + if (verbose_level >= 2) + std::cerr << "Found a k-1-face with " + << it_map_elt->second << " cofaces\n"; + + if (exit_at_the_first_problem) + return false; + else + ++num_wrong_number_of_cofaces; + } + } + + bool ret = num_wrong_dim_simplices == 0 && num_wrong_number_of_cofaces == 0; + + if (verbose_level >= 1) { + std::cerr << "Pure pseudo-manifold: "; + if (ret) { + std::cerr << green << "YES" << white << "\n"; + } else { + std::cerr << red << "NO" << white << "\n" + << " * Number of wrong dimension simplices: " + << num_wrong_dim_simplices << "\n" + << " * Number of wrong number of cofaces: " + << num_wrong_number_of_cofaces << "\n"; + } + } + + if (p_num_wrong_dim_simplices) + *p_num_wrong_dim_simplices = num_wrong_dim_simplices; + if (p_num_wrong_number_of_cofaces) + *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces; + + return ret; + } + + template + std::size_t num_K_simplices() const { + Simplex_set k_simplices; + + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + if (it_simplex->size() == K + 1) { + k_simplices.insert(*it_simplex); + } else if (it_simplex->size() > K + 1) { + // Get the k-faces composing the simplex + combinations( + *it_simplex, K + 1, std::inserter(k_simplices, k_simplices.begin())); + } + } + + return k_simplices.size(); + } + + std::ptrdiff_t euler_characteristic(bool verbose = false) const { + if (verbose) + std::cerr << "\nComputing Euler characteristic of the complex...\n"; + + std::size_t num_vertices = num_K_simplices<0>(); + std::size_t num_edges = num_K_simplices<1>(); + std::size_t num_triangles = num_K_simplices<2>(); + + std::ptrdiff_t ec = + (std::ptrdiff_t) num_vertices + - (std::ptrdiff_t) num_edges + + (std::ptrdiff_t) num_triangles; + + if (verbose) + std::cerr << "Euler characteristic: V - E + F = " + << num_vertices << " - " << num_edges << " + " << num_triangles << " = " + << blue + << ec + << white << "\n"; + + return ec; + } + + // TODO(CJ): ADD COMMENTS + + bool is_pure_pseudomanifold( + int simplex_dim, + std::size_t num_vertices, + bool allow_borders = false, + bool exit_at_the_first_problem = false, + int verbose_level = 0, + std::size_t *p_num_wrong_dim_simplices = NULL, + std::size_t *p_num_wrong_number_of_cofaces = NULL, + std::size_t *p_num_unconnected_stars = NULL, + Simplex_set *p_wrong_dim_simplices = NULL, + Simplex_set *p_wrong_number_of_cofaces_simplices = NULL, + Simplex_set *p_unconnected_stars_simplices = NULL) const { + // If simplex_dim == 1, we do not need to check if stars are connected + if (simplex_dim == 1) { + if (p_num_unconnected_stars) + *p_num_unconnected_stars = 0; + return is_pure_pseudomanifold__do_not_check_if_stars_are_connected(simplex_dim, + allow_borders, + exit_at_the_first_problem, + verbose_level, + p_num_wrong_dim_simplices, + p_num_wrong_number_of_cofaces); + } + // Associates each vertex (= the index in the vector) + // to its star (list of simplices) + typedef std::vector > Stars; + std::size_t num_wrong_dim_simplices = 0; + std::size_t num_wrong_number_of_cofaces = 0; + std::size_t num_unconnected_stars = 0; + + // Fills a Stars data structure + Stars stars; + stars.resize(num_vertices); + for (Complex::const_iterator it_simplex = m_complex.begin(), + it_simplex_end = m_complex.end(); + it_simplex != it_simplex_end; + ++it_simplex) { + if (static_cast (it_simplex->size()) != simplex_dim + 1) { + if (verbose_level >= 2) + std::cerr << "Found a simplex with dim = " + << it_simplex->size() - 1 << "\n"; + ++num_wrong_dim_simplices; + if (p_wrong_dim_simplices) + p_wrong_dim_simplices->insert(*it_simplex); + } else { + for (Simplex::const_iterator it_point_idx = it_simplex->begin(); + it_point_idx != it_simplex->end(); + ++it_point_idx) { + stars[*it_point_idx].push_back(it_simplex); + } + } + } + + // Now, for each star, we have a vector of its d-simplices + // i.e. one index for each d-simplex + // Boost Graph only deals with indexes, so we also need indexes for the + // (d-1)-simplices + std::size_t center_vertex_index = 0; + for (Stars::const_iterator it_star = stars.begin(); + it_star != stars.end(); + ++it_star, ++center_vertex_index) { + typedef std::map > + Dm1_faces_to_adj_D_faces; + Dm1_faces_to_adj_D_faces dm1_faces_to_adj_d_faces; + + for (std::size_t i_dsimpl = 0; i_dsimpl < it_star->size(); ++i_dsimpl) { + Simplex dm1_simpl_of_link = *((*it_star)[i_dsimpl]); + dm1_simpl_of_link.erase(center_vertex_index); + // Copy it to a vector so that we can use operator[] on it + std::vector dm1_simpl_of_link_vec( + dm1_simpl_of_link.begin(), dm1_simpl_of_link.end()); + + CGAL::Combination_enumerator dm2_simplices( + simplex_dim - 1, 0, simplex_dim); + for (; !dm2_simplices.finished(); ++dm2_simplices) { + Simplex dm2_simpl; + for (int j = 0; j < simplex_dim - 1; ++j) + dm2_simpl.insert(dm1_simpl_of_link_vec[dm2_simplices[j]]); + dm1_faces_to_adj_d_faces[dm2_simpl].push_back(i_dsimpl); + } + } + + Adj_graph adj_graph; + std::vector d_faces_descriptors; + d_faces_descriptors.resize(it_star->size()); + for (std::size_t j = 0; j < it_star->size(); ++j) + d_faces_descriptors[j] = boost::add_vertex(adj_graph); + + Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it = + dm1_faces_to_adj_d_faces.begin(); + Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it_end = + dm1_faces_to_adj_d_faces.end(); + for (std::size_t i_km1_face = 0; + dm1_to_d_it != dm1_to_d_it_end; + ++dm1_to_d_it, ++i_km1_face) { + Graph_vertex km1_gv = boost::add_vertex(adj_graph); + + for (std::vector::const_iterator kface_it = + dm1_to_d_it->second.begin(); + kface_it != dm1_to_d_it->second.end(); + ++kface_it) { + boost::add_edge(km1_gv, *kface_it, adj_graph); + } + + if (dm1_to_d_it->second.size() != 2 + && (!allow_borders || dm1_to_d_it->second.size() != 1)) { + ++num_wrong_number_of_cofaces; + if (p_wrong_number_of_cofaces_simplices) { + for (auto idx : dm1_to_d_it->second) + p_wrong_number_of_cofaces_simplices->insert(*((*it_star)[idx])); + } + } + } + + // What is left is to check the connexity + bool is_connected = true; + if (boost::num_vertices(adj_graph) > 0) { + std::vector components(boost::num_vertices(adj_graph)); + is_connected = + (boost::connected_components(adj_graph, &components[0]) == 1); + } + + if (!is_connected) { + if (verbose_level >= 2) + std::cerr << "Error: star #" << center_vertex_index + << " is not connected\n"; + ++num_unconnected_stars; + if (p_unconnected_stars_simplices) { + for (std::vector::const_iterator + it_simpl = it_star->begin(), + it_simpl_end = it_star->end(); + it_simpl != it_simpl_end; + ++it_simpl) { + p_unconnected_stars_simplices->insert(**it_simpl); + } + } + } + } + + // Each one has been counted several times ("simplex_dim" times) + num_wrong_number_of_cofaces /= simplex_dim; + + bool ret = + num_wrong_dim_simplices == 0 + && num_wrong_number_of_cofaces == 0 + && num_unconnected_stars == 0; + + if (verbose_level >= 1) { + std::cerr << "Pure pseudo-manifold: "; + if (ret) { + std::cerr << green << "YES" << white << "\n"; + } else { + std::cerr << red << "NO" << white << "\n" + << " * Number of wrong dimension simplices: " + << num_wrong_dim_simplices << "\n" + << " * Number of wrong number of cofaces: " + << num_wrong_number_of_cofaces << "\n" + << " * Number of not-connected stars: " + << num_unconnected_stars << "\n"; + } + } + + if (p_num_wrong_dim_simplices) + *p_num_wrong_dim_simplices = num_wrong_dim_simplices; + if (p_num_wrong_number_of_cofaces) + *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces; + if (p_num_unconnected_stars) + *p_num_unconnected_stars = num_unconnected_stars; + + return ret; + } + + private: + typedef Simplex_set Complex; + + // graph is an adjacency list + typedef boost::adjacency_list Adj_graph; + // map that gives to a certain simplex its node in graph and its dimension + typedef boost::graph_traits::vertex_descriptor Graph_vertex; + typedef boost::graph_traits::edge_descriptor Graph_edge; + + Complex m_complex; +}; // class Simplicial_complex + +} // namespace internal +} // namespace tangential_complex +} // namespace Gudhi + +#endif // TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_ diff --git a/include/gudhi/Tangential_complex/config.h b/include/gudhi/Tangential_complex/config.h new file mode 100644 index 00000000..ffefcd6b --- /dev/null +++ b/include/gudhi/Tangential_complex/config.h @@ -0,0 +1,43 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TANGENTIAL_COMPLEX_CONFIG_H_ +#define TANGENTIAL_COMPLEX_CONFIG_H_ + +#include + +// ========================= Debugging & profiling ============================= +// #define GUDHI_TC_PROFILING +// #define GUDHI_TC_VERY_VERBOSE +// #define GUDHI_TC_PERFORM_EXTRA_CHECKS +// #define GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES + +// ========================= Strategy ========================================== +#define GUDHI_TC_PERTURB_POSITION +// #define GUDHI_TC_PERTURB_WEIGHT + +// ========================= Parameters ======================================== + +// PCA will use GUDHI_TC_BASE_VALUE_FOR_PCA^intrinsic_dim points +const std::size_t GUDHI_TC_BASE_VALUE_FOR_PCA = 5; + +#endif // TANGENTIAL_COMPLEX_CONFIG_H_ diff --git a/include/gudhi/Tangential_complex/utilities.h b/include/gudhi/Tangential_complex/utilities.h new file mode 100644 index 00000000..b2d6d674 --- /dev/null +++ b/include/gudhi/Tangential_complex/utilities.h @@ -0,0 +1,195 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TANGENTIAL_COMPLEX_UTILITIES_H_ +#define TANGENTIAL_COMPLEX_UTILITIES_H_ + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include // for std::sqrt + +namespace Gudhi { +namespace tangential_complex { +namespace internal { + +// Provides copy constructors to std::atomic so that +// it can be used in a vector +template +struct Atomic_wrapper +: public std::atomic { + typedef std::atomic Base; + + Atomic_wrapper() { } + + Atomic_wrapper(const T &t) : Base(t) { } + + Atomic_wrapper(const std::atomic &a) : Base(a.load()) { } + + Atomic_wrapper(const Atomic_wrapper &other) : Base(other.load()) { } + + Atomic_wrapper &operator=(const T &other) { + Base::store(other); + return *this; + } + + Atomic_wrapper &operator=(const std::atomic &other) { + Base::store(other.load()); + return *this; + } + + Atomic_wrapper &operator=(const Atomic_wrapper &other) { + Base::store(other.load()); + return *this; + } +}; + +// Modifies v in-place +template +typename K::Vector_d& normalize_vector(typename K::Vector_d& v, + K const& k) { + v = k.scaled_vector_d_object()( + v, typename K::FT(1) / std::sqrt(k.squared_length_d_object()(v))); + return v; +} + +template +struct Basis { + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_d Point; + typedef typename Kernel::Vector_d Vector; + typedef typename std::vector::const_iterator const_iterator; + + std::size_t m_origin; + std::vector m_vectors; + + std::size_t origin() const { + return m_origin; + } + + void set_origin(std::size_t o) { + m_origin = o; + } + + const_iterator begin() const { + return m_vectors.begin(); + } + + const_iterator end() const { + return m_vectors.end(); + } + + std::size_t size() const { + return m_vectors.size(); + } + + Vector& operator[](const std::size_t i) { + return m_vectors[i]; + } + + const Vector& operator[](const std::size_t i) const { + return m_vectors[i]; + } + + void push_back(const Vector& v) { + m_vectors.push_back(v); + } + + void reserve(const std::size_t s) { + m_vectors.reserve(s); + } + + Basis() { } + + Basis(std::size_t origin) : m_origin(origin) { } + + Basis(std::size_t origin, const std::vector& vectors) + : m_origin(origin), m_vectors(vectors) { } + + int dimension() const { + return static_cast (m_vectors.size()); + } +}; + +// 1st line: number of points +// Then one point per line +template +std::ostream &export_point_set( + Kernel const& k, + Point_range const& points, + std::ostream & os, + const char *coord_separator = " ") { + // Kernel functors + typename Kernel::Construct_cartesian_const_iterator_d ccci = + k.construct_cartesian_const_iterator_d_object(); + + os << points.size() << "\n"; + + typename Point_range::const_iterator it_p = points.begin(); + typename Point_range::const_iterator it_p_end = points.end(); + // For each point p + for (; it_p != it_p_end; ++it_p) { + for (auto it = ccci(*it_p); it != ccci(*it_p, 0); ++it) + os << CGAL::to_double(*it) << coord_separator; + + os << "\n"; + } + + return os; +} + +// Compute all the k-combinations of elements +// Output_iterator::value_type must be +// boost::container::flat_set +template +void combinations(const Elements_container elements, int k, + Output_iterator combinations) { + std::size_t n = elements.size(); + std::vector booleans(n, false); + std::fill(booleans.begin() + n - k, booleans.end(), true); + do { + boost::container::flat_set combination; + typename Elements_container::const_iterator it_elt = elements.begin(); + for (std::size_t i = 0; i < n; ++i, ++it_elt) { + if (booleans[i]) + combination.insert(*it_elt); + } + *combinations++ = combination; + } while (std::next_permutation(booleans.begin(), booleans.end())); +} + +} // namespace internal +} // namespace tangential_complex +} // namespace Gudhi + +#endif // TANGENTIAL_COMPLEX_UTILITIES_H_ diff --git a/include/gudhi/Test.h b/include/gudhi/Test.h deleted file mode 100644 index 6024c822..00000000 --- a/include/gudhi/Test.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * - * Author(s): David Salinas - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Mediterranee (France) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#ifndef TEST_H_ -#define TEST_H_ - -#include -#include -#include -#include -#include - - -#define TEST(a) std::cout << "TEST: " << (a) << std::endl -#define TESTMSG(a, b) std::cout << "TEST: " << a << b << std::endl -#define TESTVALUE(a) std::cout << "TEST: " << #a << ": " << a << std::endl - -/** - * Class to perform test - */ - -class Test { - private: - std::string name; - bool (*test)(); - - std::string separation() const { - return "+++++++++++++++++++++++++++++++++++++++++++++++++\n"; - } - - std::string print_between_plus(std::string& s) const { - std::stringstream res; - res << "+++++++++++++++++" << s << "+++++++++++++++++\n"; - return res.str(); - } - - public: - Test(std::string name_, bool (*test_)()) { - name = name_; - test = test_; - } - - bool run() { - std::cout << print_between_plus(name); - return test(); - } - - std::string getName() { - return name; - } -}; - -class Tests { - private: - std::list tests; - - public: - void add(std::string name_, bool (*test_)()) { - Test test(name_, test_); - tests.push_back(test); - } - - bool run() { - bool tests_succesful(true); - std::vector res; - for (Test test : tests) { - res.push_back(test.run()); - } - std::cout << "\n\n results of tests : " << std::endl; - int i = 0; - for (Test t : tests) { - std::cout << "Test " << i << " \"" << t.getName() << "\" --> "; - if (res[i++]) { - std::cout << "OK" << std::endl; - } else { - std::cout << "Fail" << std::endl; - tests_succesful = false; - break; - } - } - return tests_succesful; - } -}; - -#endif // TEST_H_ diff --git a/include/gudhi/Witness_complex.h b/include/gudhi/Witness_complex.h index 489cdf11..63f03687 100644 --- a/include/gudhi/Witness_complex.h +++ b/include/gudhi/Witness_complex.h @@ -4,7 +4,7 @@ * * Author(s): Siargey Kachanovich * - * Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2015 INRIA (France) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,65 +23,44 @@ #ifndef WITNESS_COMPLEX_H_ #define WITNESS_COMPLEX_H_ -// Needed for the adjacency graph in bad link search -#include -#include -#include +#include +#include -#include - -#include - -#include #include #include #include -#include -#include #include -#include -#include namespace Gudhi { namespace witness_complex { -// /* -// * \private -// \class Witness_complex -// \brief Constructs the witness complex for the given set of witnesses and landmarks. -// \ingroup witness_complex -// */ -template< class SimplicialComplex> +/** + * \private + * \class Witness_complex + * \brief Constructs (weak) witness complex for a given table of nearest landmarks with respect to witnesses. + * \ingroup witness_complex + * + * \tparam Nearest_landmark_table_ needs to be a range of a range of pairs of nearest landmarks and distances. + * The class Nearest_landmark_table_::value_type must be a copiable range. + * The range of pairs must admit a member type 'iterator'. The dereference type + * of the pair range iterator needs to be 'std::pair'. +*/ +template< class Nearest_landmark_table_ > class Witness_complex { private: - struct Active_witness { - int witness_id; - int landmark_id; - - Active_witness(int witness_id_, int landmark_id_) - : witness_id(witness_id_), - landmark_id(landmark_id_) { } - }; - - private: - typedef typename SimplicialComplex::Simplex_handle Simplex_handle; - typedef typename SimplicialComplex::Vertex_handle Vertex_handle; - - typedef std::vector< double > Point_t; - typedef std::vector< Point_t > Point_Vector; - - typedef std::vector< Vertex_handle > typeVectorVertex; - typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex; - typedef std::pair< Simplex_handle, bool > typePairSimplexBool; - - typedef int Witness_id; - typedef int Landmark_id; - typedef std::list< Vertex_handle > ActiveWitnessList; - - private: - int nbL_; // Number of landmarks - SimplicialComplex& sc_; // Simplicial complex + typedef typename Nearest_landmark_table_::value_type Nearest_landmark_range; + typedef std::size_t Witness_id; + typedef std::size_t Landmark_id; + typedef std::pair Id_distance_pair; + typedef Active_witness ActiveWitness; + typedef std::list< ActiveWitness > ActiveWitnessList; + typedef std::vector< Landmark_id > typeVectorVertex; + typedef std::vector Nearest_landmark_table_internal; + typedef Landmark_id Vertex_handle; + + protected: + Nearest_landmark_table_internal nearest_landmark_table_; public: ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -90,174 +69,136 @@ class Witness_complex { //@{ - // Witness_range> + Witness_complex() { + } - /* - * \brief Iterative construction of the witness complex. - * \details The witness complex is written in sc_ basing on a matrix knn of - * nearest neighbours of the form {witnesses}x{landmarks}. - * - * The type KNearestNeighbors can be seen as - * Witness_range>, where - * Witness_range and Closest_landmark_range are random access ranges. - * - * Constructor takes into account at most (dim+1) - * first landmarks from each landmark range to construct simplices. - * - * Landmarks are supposed to be in [0,nbL_-1] + /** + * \brief Initializes member variables before constructing simplicial complex. + * \details Records nearest landmark table. + * @param[in] nearest_landmark_table needs to be a range of a range of pairs of nearest landmarks and distances. + * The class Nearest_landmark_table_::value_type must be a copiable range. + * The range of pairs must admit a member type 'iterator'. The dereference type + * of the pair range iterator needs to be 'std::pair'. */ - template< typename KNearestNeighbors > - Witness_complex(KNearestNeighbors const & knn, - int nbL, - int dim, - SimplicialComplex & sc) : nbL_(nbL), sc_(sc) { - // Construction of the active witness list - int nbW = boost::size(knn); - typeVectorVertex vv; - int counter = 0; - /* The list of still useful witnesses - * it will diminuish in the course of iterations - */ - ActiveWitnessList active_w; // = new ActiveWitnessList(); - for (Vertex_handle i = 0; i != nbL_; ++i) { - // initial fill of 0-dimensional simplices - // by doing it we don't assume that landmarks are necessarily witnesses themselves anymore - counter++; - vv = {i}; - sc_.insert_simplex(vv); - // TODO(SK) Error if not inserted : normally no need here though + + Witness_complex(Nearest_landmark_table_ const & nearest_landmark_table) + : nearest_landmark_table_(std::begin(nearest_landmark_table), std::end(nearest_landmark_table)) { + } + + /** \brief Outputs the (weak) witness complex of relaxation 'max_alpha_square' + * in a simplicial complex data structure. + * \details The function returns true if the construction is successful and false otherwise. + * @param[out] complex Simplicial complex data structure compatible which is a model of + * SimplicialComplexForWitness concept. + * @param[in] max_alpha_square Maximal squared relaxation parameter. + * @param[in] limit_dimension Represents the maximal dimension of the simplicial complex + * (default value = no limit). + */ + template < typename SimplicialComplexForWitness > + bool create_complex(SimplicialComplexForWitness& complex, + double max_alpha_square, + std::size_t limit_dimension = std::numeric_limits::max()) const { + if (complex.num_vertices() > 0) { + std::cerr << "Witness complex cannot create complex - complex is not empty.\n"; + return false; } - int k = 1; /* current dimension in iterative construction */ - for (int i = 0; i != nbW; ++i) - active_w.push_back(i); - while (!active_w.empty() && k < dim) { - typename ActiveWitnessList::iterator it = active_w.begin(); - while (it != active_w.end()) { - typeVectorVertex simplex_vector; - /* THE INSERTION: Checking if all the subfaces are in the simplex tree*/ - bool ok = all_faces_in(knn, *it, k); - if (ok) { - for (int i = 0; i != k + 1; ++i) - simplex_vector.push_back(knn[*it][i]); - sc_.insert_simplex(simplex_vector); - // TODO(SK) Error if not inserted : normally no need here though - ++it; - } else { - active_w.erase(it++); // First increase the iterator and then erase the previous element - } + if (max_alpha_square < 0) { + std::cerr << "Witness complex cannot create complex - squared relaxation parameter must be non-negative.\n"; + return false; + } + if (limit_dimension < 0) { + std::cerr << "Witness complex cannot create complex - limit dimension must be non-negative.\n"; + return false; + } + ActiveWitnessList active_witnesses; + Landmark_id k = 0; /* current dimension in iterative construction */ + for (auto w : nearest_landmark_table_) + active_witnesses.push_back(ActiveWitness(w)); + while (!active_witnesses.empty() && k <= limit_dimension) { + typename ActiveWitnessList::iterator aw_it = active_witnesses.begin(); + std::vector simplex; + simplex.reserve(k+1); + while (aw_it != active_witnesses.end()) { + bool ok = add_all_faces_of_dimension(k, + max_alpha_square, + std::numeric_limits::infinity(), + aw_it->begin(), + simplex, + complex, + aw_it->end()); + assert(simplex.empty()); + if (!ok) + active_witnesses.erase(aw_it++); // First increase the iterator and then erase the previous element + else + aw_it++; } k++; } + complex.set_dimension(k-1); + return true; } //@} private: - /* \brief Check if the facets of the k-dimensional simplex witnessed - * by witness witness_id are already in the complex. - * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id + /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness. + * Iterator is needed to know until how far we can take landmarks to form simplexes. + * simplex is the prefix of the simplexes to insert. + * The output value indicates if the witness rests active or not. */ - template - bool all_faces_in(KNearestNeighbors const &knn, int witness_id, int k) { - std::vector< Vertex_handle > facet; - // CHECK ALL THE FACETS - for (int i = 0; i != k + 1; ++i) { - facet = {}; - for (int j = 0; j != k + 1; ++j) { - if (j != i) { - facet.push_back(knn[witness_id][j]); + template < typename SimplicialComplexForWitness > + bool add_all_faces_of_dimension(int dim, + double alpha2, + double norelax_dist2, + typename ActiveWitness::iterator curr_l, + std::vector& simplex, + SimplicialComplexForWitness& sc, + typename ActiveWitness::iterator end) const { + if (curr_l == end) + return false; + bool will_be_active = false; + typename ActiveWitness::iterator l_it = curr_l; + if (dim > 0) { + for (; l_it != end && l_it->second - alpha2 <= norelax_dist2; ++l_it) { + simplex.push_back(l_it->first); + if (sc.find(simplex) != sc.null_simplex()) { + typename ActiveWitness::iterator next_it = l_it; + will_be_active = add_all_faces_of_dimension(dim-1, + alpha2, + norelax_dist2, + ++next_it, + simplex, + sc, + end) || will_be_active; } - } // endfor - if (sc_.find(facet) == sc_.null_simplex()) - return false; - } // endfor - return true; - } - - template - static void print_vector(const std::vector& v) { - std::cout << "["; - if (!v.empty()) { - std::cout << *(v.begin()); - for (auto it = v.begin() + 1; it != v.end(); ++it) { - std::cout << ","; - std::cout << *it; + assert(!simplex.empty()); + simplex.pop_back(); + // If norelax_dist is infinity, change to first omitted distance + if (l_it->second <= norelax_dist2) + norelax_dist2 = l_it->second; } - } - std::cout << "]"; - } - - public: - // /* - // * \brief Verification if every simplex in the complex is witnessed by witnesses in knn. - // * \param print_output =true will print the witnesses for each simplex - // * \remark Added for debugging purposes. - // */ - template< class KNearestNeighbors > - bool is_witness_complex(KNearestNeighbors const & knn, bool print_output) { - for (Simplex_handle sh : sc_.complex_simplex_range()) { - bool is_witnessed = false; - typeVectorVertex simplex; - int nbV = 0; // number of verticed in the simplex - for (Vertex_handle v : sc_.simplex_vertex_range(sh)) - simplex.push_back(v); - nbV = simplex.size(); - for (typeVectorVertex w : knn) { - bool has_vertices = true; - for (Vertex_handle v : simplex) - if (std::find(w.begin(), w.begin() + nbV, v) == w.begin() + nbV) { - has_vertices = false; - } - if (has_vertices) { - is_witnessed = true; - if (print_output) { - std::cout << "The simplex "; - print_vector(simplex); - std::cout << " is witnessed by the witness "; - print_vector(w); - std::cout << std::endl; - } - break; - } - } - if (!is_witnessed) { - if (print_output) { - std::cout << "The following simplex is not witnessed "; - print_vector(simplex); - std::cout << std::endl; + } else if (dim == 0) { + for (; l_it != end && l_it->second - alpha2 <= norelax_dist2; ++l_it) { + simplex.push_back(l_it->first); + double filtration_value = 0; + // if norelax_dist is infinite, relaxation is 0. + if (l_it->second > norelax_dist2) + filtration_value = l_it->second - norelax_dist2; + if (all_faces_in(simplex, &filtration_value, sc)) { + will_be_active = true; + sc.insert_simplex(simplex, filtration_value); } - assert(is_witnessed); - return false; + assert(!simplex.empty()); + simplex.pop_back(); + // If norelax_dist is infinity, change to first omitted distance + if (l_it->second < norelax_dist2) + norelax_dist2 = l_it->second; } } - return true; + return will_be_active; } }; - /** - * \ingroup witness_complex - * \brief Iterative construction of the witness complex. - * \details The witness complex is written in simplicial complex sc_ - * basing on a matrix knn of - * nearest neighbours of the form {witnesses}x{landmarks}. - * - * The type KNearestNeighbors can be seen as - * Witness_range>, where - * Witness_range and Closest_landmark_range are random access ranges. - * - * Procedure takes into account at most (dim+1) - * first landmarks from each landmark range to construct simplices. - * - * Landmarks are supposed to be in [0,nbL_-1] - */ - template - void witness_complex(KNearestNeighbors const & knn, - int nbL, - int dim, - SimplicialComplexForWitness & sc) { - Witness_complex(knn, nbL, dim, sc); - } - } // namespace witness_complex } // namespace Gudhi diff --git a/include/gudhi/Witness_complex/all_faces_in.h b/include/gudhi/Witness_complex/all_faces_in.h new file mode 100644 index 00000000..b68d75a1 --- /dev/null +++ b/include/gudhi/Witness_complex/all_faces_in.h @@ -0,0 +1,55 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2015 INRIA (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WITNESS_COMPLEX_ALL_FACES_IN_H_ +#define WITNESS_COMPLEX_ALL_FACES_IN_H_ + +/* \brief Check if the facets of the k-dimensional simplex witnessed + * by witness witness_id are already in the complex. + * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id + */ +template < typename SimplicialComplexForWitness, + typename Simplex > + bool all_faces_in(Simplex& simplex, + double* filtration_value, + SimplicialComplexForWitness& sc) { + typedef typename SimplicialComplexForWitness::Simplex_handle Simplex_handle; + + if (simplex.size() == 1) + return true; /* Add vertices unconditionally */ + + Simplex facet; + for (typename Simplex::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it) { + facet.clear(); + for (typename Simplex::iterator it = simplex.begin(); it != simplex.end(); ++it) + if (it != not_it) + facet.push_back(*it); + Simplex_handle facet_sh = sc.find(facet); + if (facet_sh == sc.null_simplex()) + return false; + else if (sc.filtration(facet_sh) > *filtration_value) + *filtration_value = sc.filtration(facet_sh); + } + return true; + } + +#endif // WITNESS_COMPLEX_ALL_FACES_IN_H_ diff --git a/include/gudhi/choose_n_farthest_points.h b/include/gudhi/choose_n_farthest_points.h new file mode 100644 index 00000000..86500b28 --- /dev/null +++ b/include/gudhi/choose_n_farthest_points.h @@ -0,0 +1,133 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CHOOSE_N_FARTHEST_POINTS_H_ +#define CHOOSE_N_FARTHEST_POINTS_H_ + +#include + +#include + +#include +#include +#include +#include // for numeric_limits<> + +namespace Gudhi { + +namespace subsampling { + +/** + * \ingroup subsampling + */ +enum : std::size_t { +/** + * Argument for `choose_n_farthest_points` to indicate that the starting point should be picked randomly. + */ + random_starting_point = std::size_t(-1) +}; + +/** + * \ingroup subsampling + * \brief Subsample by a greedy strategy of iteratively adding the farthest point from the + * current chosen point set to the subsampling. + * The iteration starts with the landmark `starting point` or, if `starting point==random_starting_point`, with a random landmark. + * \tparam Kernel must provide a type Kernel::Squared_distance_d which is a model of the + * concept Kernel_d::Squared_distance_d (despite the name, taken from CGAL, this can be any kind of metric or proximity measure). + * It must also contain a public member `squared_distance_d_object()` that returns an object of this type. + * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access + * via `operator[]` and the points should be stored contiguously in memory. + * \tparam PointOutputIterator Output iterator whose value type is Kernel::Point_d. + * \tparam DistanceOutputIterator Output iterator for distances. + * \details It chooses `final_size` points from a random access range + * `input_pts` and outputs them in the output iterator `output_it`. It also + * outputs the distance from each of those points to the set of previous + * points in `dist_it`. + * @param[in] k A kernel object. + * @param[in] input_pts Const reference to the input points. + * @param[in] final_size The size of the subsample to compute. + * @param[in] starting_point The seed in the farthest point algorithm. + * @param[out] output_it The output iterator for points. + * @param[out] dist_it The optional output iterator for distances. + * + */ +template < typename Kernel, +typename Point_range, +typename PointOutputIterator, +typename DistanceOutputIterator = Null_output_iterator> +void choose_n_farthest_points(Kernel const &k, + Point_range const &input_pts, + std::size_t final_size, + std::size_t starting_point, + PointOutputIterator output_it, + DistanceOutputIterator dist_it = {}) { + std::size_t nb_points = boost::size(input_pts); + if (final_size > nb_points) + final_size = nb_points; + + // Tests to the limit + if (final_size < 1) + return; + + if (starting_point == random_starting_point) { + // Choose randomly the first landmark + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, (input_pts.size() - 1)); + starting_point = dis(gen); + } + + typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object(); + + std::size_t current_number_of_landmarks = 0; // counter for landmarks + const double infty = std::numeric_limits::infinity(); // infinity (see next entry) + std::vector< double > dist_to_L(nb_points, infty); // vector of current distances to L from input_pts + + std::size_t curr_max_w = starting_point; + + for (current_number_of_landmarks = 0; current_number_of_landmarks != final_size; current_number_of_landmarks++) { + // curr_max_w at this point is the next landmark + *output_it++ = input_pts[curr_max_w]; + *dist_it++ = dist_to_L[curr_max_w]; + std::size_t i = 0; + for (auto& p : input_pts) { + double curr_dist = sqdist(p, *(std::begin(input_pts) + curr_max_w)); + if (curr_dist < dist_to_L[i]) + dist_to_L[i] = curr_dist; + ++i; + } + // choose the next curr_max_w + double curr_max_dist = 0; // used for defining the furhest point from L + for (i = 0; i < dist_to_L.size(); i++) + if (dist_to_L[i] > curr_max_dist) { + curr_max_dist = dist_to_L[i]; + curr_max_w = i; + } + } +} + +} // namespace subsampling + +} // namespace Gudhi + +#endif // CHOOSE_N_FARTHEST_POINTS_H_ diff --git a/include/gudhi/console_color.h b/include/gudhi/console_color.h new file mode 100644 index 00000000..c4671da3 --- /dev/null +++ b/include/gudhi/console_color.h @@ -0,0 +1,97 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA Sophia-Antipolis (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONSOLE_COLOR_H_ +#define CONSOLE_COLOR_H_ + +#include + +#if defined(WIN32) +#include +#endif + +inline std::ostream& blue(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); +#else + s << "\x1b[0;34m"; +#endif + return s; +} + +inline std::ostream& red(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY); +#else + s << "\x1b[0;31m"; +#endif + return s; +} + +inline std::ostream& green(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY); +#else + s << "\x1b[0;32m"; +#endif + return s; +} + +inline std::ostream& yellow(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, + FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); +#else + s << "\x1b[0;33m"; +#endif + return s; +} + +inline std::ostream& white(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); +#else + s << "\x1b[0;37m"; +#endif + return s; +} + +inline std::ostream& black_on_white(std::ostream &s) { +#if defined(WIN32) + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hStdout, + BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); +#else + s << "\x1b[0;33m"; +#endif + return s; +} + + +#endif // CONSOLE_COLOR_H_ diff --git a/include/gudhi/distance_functions.h b/include/gudhi/distance_functions.h index cd518581..f6e2ab5a 100644 --- a/include/gudhi/distance_functions.h +++ b/include/gudhi/distance_functions.h @@ -4,7 +4,7 @@ * * Author(s): Clément Maria * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,20 +24,32 @@ #define DISTANCE_FUNCTIONS_H_ #include // for std::sqrt +#include // for std::decay +#include // for std::begin, std::end -/* Compute the Euclidean distance between two Points given - * by a range of coordinates. The points are assumed to have - * the same dimension. */ -template< typename Point > -double euclidean_distance(Point &p1, Point &p2) { - double dist = 0.; - auto it1 = p1.begin(); - auto it2 = p2.begin(); - for (; it1 != p1.end(); ++it1, ++it2) { - double tmp = *it1 - *it2; - dist += tmp*tmp; +namespace Gudhi { + +/** @file + * @brief Global distance functions + */ + +/** @brief Compute the Euclidean distance between two Points given by a range of coordinates. The points are assumed to + * have the same dimension. */ +class Euclidean_distance { + public: + template< typename Point > + auto operator()(const Point& p1, const Point& p2) const -> typename std::decay::type { + auto it1 = p1.begin(); + auto it2 = p2.begin(); + typename Point::value_type dist = 0.; + for (; it1 != p1.end(); ++it1, ++it2) { + typename Point::value_type tmp = (*it1) - (*it2); + dist += tmp*tmp; + } + return std::sqrt(dist); } - return std::sqrt(dist); -} +}; + +} // namespace Gudhi #endif // DISTANCE_FUNCTIONS_H_ diff --git a/include/gudhi/graph_simplicial_complex.h b/include/gudhi/graph_simplicial_complex.h index 042ef516..5fe7c826 100644 --- a/include/gudhi/graph_simplicial_complex.h +++ b/include/gudhi/graph_simplicial_complex.h @@ -4,7 +4,7 @@ * * Author(s): Clément Maria * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,61 +39,4 @@ struct vertex_filtration_t { typedef boost::vertex_property_tag kind; }; -typedef int Vertex_handle; -typedef double Filtration_value; -typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS -, boost::property < vertex_filtration_t, Filtration_value > -, boost::property < edge_filtration_t, Filtration_value > -> Graph_t; -typedef std::pair< Vertex_handle, Vertex_handle > Edge_t; - -/** \brief Output the proximity graph of the points. - * - * If points contains n elements, the proximity graph is the graph - * with n vertices, and an edge [u,v] iff the distance function between - * points u and v is smaller than threshold. - * - * The type PointCloud furnishes .begin() and .end() methods, that return - * iterators with value_type Point. - */ -template< typename PointCloud -, typename Point > -Graph_t compute_proximity_graph(PointCloud &points - , Filtration_value threshold - , Filtration_value distance(Point p1, Point p2)) { - std::vector< Edge_t > edges; - std::vector< Filtration_value > edges_fil; - std::map< Vertex_handle, Filtration_value > vertices; - - Vertex_handle idx_u, idx_v; - Filtration_value fil; - idx_u = 0; - for (auto it_u = points.begin(); it_u != points.end(); ++it_u) { - idx_v = idx_u + 1; - for (auto it_v = it_u + 1; it_v != points.end(); ++it_v, ++idx_v) { - fil = distance(*it_u, *it_v); - if (fil <= threshold) { - edges.emplace_back(idx_u, idx_v); - edges_fil.push_back(fil); - } - } - ++idx_u; - } - - Graph_t skel_graph(edges.begin() - , edges.end() - , edges_fil.begin() - , idx_u); // number of points labeled from 0 to idx_u-1 - - auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph); - - boost::graph_traits::vertex_iterator vi, vi_end; - for (std::tie(vi, vi_end) = boost::vertices(skel_graph); - vi != vi_end; ++vi) { - boost::put(vertex_prop, *vi, 0.); - } - - return skel_graph; -} - #endif // GRAPH_SIMPLICIAL_COMPLEX_H_ diff --git a/include/gudhi/pick_n_random_points.h b/include/gudhi/pick_n_random_points.h new file mode 100644 index 00000000..f0e3f1f1 --- /dev/null +++ b/include/gudhi/pick_n_random_points.h @@ -0,0 +1,86 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Siargey Kachanovich + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PICK_N_RANDOM_POINTS_H_ +#define PICK_N_RANDOM_POINTS_H_ + +#include + +#include + +#include +#include // random_device, mt19937 +#include // shuffle +#include // iota +#include +#include + + +namespace Gudhi { + +namespace subsampling { + +/** + * \ingroup subsampling + * \brief Subsample a point set by picking random vertices. + * + * \details It chooses `final_size` distinct points from a random access range `points` + * and outputs them to the output iterator `output_it`. + * Point_container::iterator should be ValueSwappable and RandomAccessIterator. + */ +template +void pick_n_random_points(Point_container const &points, + std::size_t final_size, + OutputIterator output_it) { +#ifdef GUDHI_SUBS_PROFILING + Gudhi::Clock t; +#endif + + std::size_t nbP = boost::size(points); + if (final_size > nbP) + final_size = nbP; + + std::vector landmarks(nbP); + std::iota(landmarks.begin(), landmarks.end(), 0); + + std::random_device rd; + std::mt19937 g(rd()); + + std::shuffle(landmarks.begin(), landmarks.end(), g); + landmarks.resize(final_size); + + for (int l : landmarks) + *output_it++ = points[l]; + +#ifdef GUDHI_SUBS_PROFILING + t.end(); + std::cerr << "Random landmark choice took " << t.num_seconds() + << " seconds." << std::endl; +#endif +} + +} // namespace subsampling + +} // namespace Gudhi + +#endif // PICK_N_RANDOM_POINTS_H_ diff --git a/include/gudhi/random_point_generators.h b/include/gudhi/random_point_generators.h new file mode 100644 index 00000000..2ec465ef --- /dev/null +++ b/include/gudhi/random_point_generators.h @@ -0,0 +1,474 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef RANDOM_POINT_GENERATORS_H_ +#define RANDOM_POINT_GENERATORS_H_ + +#include +#include +#include + +#include // for vector<> + +namespace Gudhi { + +/////////////////////////////////////////////////////////////////////////////// +// Note: All these functions have been tested with the CGAL::Epick_d kernel +/////////////////////////////////////////////////////////////////////////////// + +// construct_point: dim 2 + +template +typename Kernel::Point_d construct_point(const Kernel &k, + typename Kernel::FT x1, typename Kernel::FT x2) { + typename Kernel::FT tab[2]; + tab[0] = x1; + tab[1] = x2; + return k.construct_point_d_object()(2, &tab[0], &tab[2]); +} + +// construct_point: dim 3 + +template +typename Kernel::Point_d construct_point(const Kernel &k, + typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3) { + typename Kernel::FT tab[3]; + tab[0] = x1; + tab[1] = x2; + tab[2] = x3; + return k.construct_point_d_object()(3, &tab[0], &tab[3]); +} + +// construct_point: dim 4 + +template +typename Kernel::Point_d construct_point(const Kernel &k, + typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3, + typename Kernel::FT x4) { + typename Kernel::FT tab[4]; + tab[0] = x1; + tab[1] = x2; + tab[2] = x3; + tab[3] = x4; + return k.construct_point_d_object()(4, &tab[0], &tab[4]); +} + +// construct_point: dim 5 + +template +typename Kernel::Point_d construct_point(const Kernel &k, + typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3, + typename Kernel::FT x4, typename Kernel::FT x5) { + typename Kernel::FT tab[5]; + tab[0] = x1; + tab[1] = x2; + tab[2] = x3; + tab[3] = x4; + tab[4] = x5; + return k.construct_point_d_object()(5, &tab[0], &tab[5]); +} + +// construct_point: dim 6 + +template +typename Kernel::Point_d construct_point(const Kernel &k, + typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3, + typename Kernel::FT x4, typename Kernel::FT x5, typename Kernel::FT x6) { + typename Kernel::FT tab[6]; + tab[0] = x1; + tab[1] = x2; + tab[2] = x3; + tab[3] = x4; + tab[4] = x5; + tab[5] = x6; + return k.construct_point_d_object()(6, &tab[0], &tab[6]); +} + +template +std::vector generate_points_on_plane(std::size_t num_points, int intrinsic_dim, + int ambient_dim, + double coord_min = -5., double coord_max = 5.) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + std::vector pt(ambient_dim, FT(0)); + for (int j = 0; j < intrinsic_dim; ++j) + pt[j] = rng.get_double(coord_min, coord_max); + + Point p = k.construct_point_d_object()(ambient_dim, pt.begin(), pt.end()); + points.push_back(p); + ++i; + } + return points; +} + +template +std::vector generate_points_on_moment_curve(std::size_t num_points, int dim, + typename Kernel::FT min_x, + typename Kernel::FT max_x) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + FT x = rng.get_double(min_x, max_x); + std::vector coords; + coords.reserve(dim); + for (int p = 1; p <= dim; ++p) + coords.push_back(std::pow(CGAL::to_double(x), p)); + Point p = k.construct_point_d_object()( + dim, coords.begin(), coords.end()); + points.push_back(p); + ++i; + } + return points; +} + + +// R = big radius, r = small radius +template +std::vector generate_points_on_torus_3D(std::size_t num_points, double R, double r, + bool uniform = false) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + + // if uniform + std::size_t num_lines = (std::size_t)sqrt(num_points); + + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + FT u, v; + if (uniform) { + std::size_t k1 = i / num_lines; + std::size_t k2 = i % num_lines; + u = 6.2832 * k1 / num_lines; + v = 6.2832 * k2 / num_lines; + } else { + u = rng.get_double(0, 6.2832); + v = rng.get_double(0, 6.2832); + } + Point p = construct_point(k, + (R + r * std::cos(u)) * std::cos(v), + (R + r * std::cos(u)) * std::sin(v), + r * std::sin(u)); + points.push_back(p); + ++i; + } + return points; +} + +// "Private" function used by generate_points_on_torus_d +template +static void generate_uniform_points_on_torus_d(const Kernel &k, int dim, std::size_t num_slices, + OutputIterator out, + double radius_noise_percentage = 0., + std::vector current_point = std::vector()) { + CGAL::Random rng; + int point_size = static_cast(current_point.size()); + if (point_size == 2 * dim) { + *out++ = k.construct_point_d_object()(point_size, current_point.begin(), current_point.end()); + } else { + for (std::size_t slice_idx = 0; slice_idx < num_slices; ++slice_idx) { + double radius_noise_ratio = 1.; + if (radius_noise_percentage > 0.) { + radius_noise_ratio = rng.get_double( + (100. - radius_noise_percentage) / 100., + (100. + radius_noise_percentage) / 100.); + } + std::vector cp2 = current_point; + double alpha = 6.2832 * slice_idx / num_slices; + cp2.push_back(radius_noise_ratio * std::cos(alpha)); + cp2.push_back(radius_noise_ratio * std::sin(alpha)); + generate_uniform_points_on_torus_d( + k, dim, num_slices, out, radius_noise_percentage, cp2); + } + } +} + +template +std::vector generate_points_on_torus_d(std::size_t num_points, int dim, bool uniform = false, + double radius_noise_percentage = 0.) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + + std::vector points; + points.reserve(num_points); + if (uniform) { + std::size_t num_slices = (std::size_t)std::pow(num_points, 1. / dim); + generate_uniform_points_on_torus_d( + k, dim, num_slices, std::back_inserter(points), radius_noise_percentage); + } else { + for (std::size_t i = 0; i < num_points;) { + double radius_noise_ratio = 1.; + if (radius_noise_percentage > 0.) { + radius_noise_ratio = rng.get_double( + (100. - radius_noise_percentage) / 100., + (100. + radius_noise_percentage) / 100.); + } + std::vector pt; + pt.reserve(dim * 2); + for (int curdim = 0; curdim < dim; ++curdim) { + FT alpha = rng.get_double(0, 6.2832); + pt.push_back(radius_noise_ratio * std::cos(alpha)); + pt.push_back(radius_noise_ratio * std::sin(alpha)); + } + + Point p = k.construct_point_d_object()(pt.begin(), pt.end()); + points.push_back(p); + ++i; + } + } + return points; +} + +template +std::vector generate_points_on_sphere_d(std::size_t num_points, int dim, double radius, + double radius_noise_percentage = 0.) { + typedef typename Kernel::Point_d Point; + Kernel k; + CGAL::Random rng; + CGAL::Random_points_on_sphere_d generator(dim, radius); + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + Point p = *generator++; + if (radius_noise_percentage > 0.) { + double radius_noise_ratio = rng.get_double( + (100. - radius_noise_percentage) / 100., + (100. + radius_noise_percentage) / 100.); + + typename Kernel::Point_to_vector_d k_pt_to_vec = + k.point_to_vector_d_object(); + typename Kernel::Vector_to_point_d k_vec_to_pt = + k.vector_to_point_d_object(); + typename Kernel::Scaled_vector_d k_scaled_vec = + k.scaled_vector_d_object(); + p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio)); + } + points.push_back(p); + ++i; + } + return points; +} + +template +std::vector generate_points_on_two_spheres_d(std::size_t num_points, int dim, double radius, + double distance_between_centers, + double radius_noise_percentage = 0.) { + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_d Point; + typedef typename Kernel::Vector_d Vector; + Kernel k; + CGAL::Random rng; + CGAL::Random_points_on_sphere_d generator(dim, radius); + std::vector points; + points.reserve(num_points); + + std::vector t(dim, FT(0)); + t[0] = distance_between_centers; + Vector c1_to_c2(t.begin(), t.end()); + + for (std::size_t i = 0; i < num_points;) { + Point p = *generator++; + if (radius_noise_percentage > 0.) { + double radius_noise_ratio = rng.get_double( + (100. - radius_noise_percentage) / 100., + (100. + radius_noise_percentage) / 100.); + + typename Kernel::Point_to_vector_d k_pt_to_vec = + k.point_to_vector_d_object(); + typename Kernel::Vector_to_point_d k_vec_to_pt = + k.vector_to_point_d_object(); + typename Kernel::Scaled_vector_d k_scaled_vec = + k.scaled_vector_d_object(); + p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio)); + } + + typename Kernel::Translated_point_d k_transl = + k.translated_point_d_object(); + Point p2 = k_transl(p, c1_to_c2); + points.push_back(p); + points.push_back(p2); + i += 2; + } + return points; +} + +// Product of a 3-sphere and a circle => d = 3 / D = 5 + +template +std::vector generate_points_on_3sphere_and_circle(std::size_t num_points, + double sphere_radius) { + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_d Point; + Kernel k; + CGAL::Random rng; + CGAL::Random_points_on_sphere_d generator(3, sphere_radius); + std::vector points; + points.reserve(num_points); + + typename Kernel::Compute_coordinate_d k_coord = + k.compute_coordinate_d_object(); + for (std::size_t i = 0; i < num_points;) { + Point p_sphere = *generator++; // First 3 coords + + FT alpha = rng.get_double(0, 6.2832); + std::vector pt(5); + pt[0] = k_coord(p_sphere, 0); + pt[1] = k_coord(p_sphere, 1); + pt[2] = k_coord(p_sphere, 2); + pt[3] = std::cos(alpha); + pt[4] = std::sin(alpha); + Point p(pt.begin(), pt.end()); + points.push_back(p); + ++i; + } + return points; +} + +// a = big radius, b = small radius +template +std::vector generate_points_on_klein_bottle_3D(std::size_t num_points, double a, double b, + bool uniform = false) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + + // if uniform + std::size_t num_lines = (std::size_t)sqrt(num_points); + + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + FT u, v; + if (uniform) { + std::size_t k1 = i / num_lines; + std::size_t k2 = i % num_lines; + u = 6.2832 * k1 / num_lines; + v = 6.2832 * k2 / num_lines; + } else { + u = rng.get_double(0, 6.2832); + v = rng.get_double(0, 6.2832); + } + double tmp = cos(u / 2) * sin(v) - sin(u / 2) * sin(2. * v); + Point p = construct_point(k, + (a + b * tmp) * cos(u), + (a + b * tmp) * sin(u), + b * (sin(u / 2) * sin(v) + cos(u / 2) * sin(2. * v))); + points.push_back(p); + ++i; + } + return points; +} + +// a = big radius, b = small radius +template +std::vector generate_points_on_klein_bottle_4D(std::size_t num_points, double a, double b, + double noise = 0., bool uniform = false) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + + // if uniform + std::size_t num_lines = (std::size_t)sqrt(num_points); + + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + FT u, v; + if (uniform) { + std::size_t k1 = i / num_lines; + std::size_t k2 = i % num_lines; + u = 6.2832 * k1 / num_lines; + v = 6.2832 * k2 / num_lines; + } else { + u = rng.get_double(0, 6.2832); + v = rng.get_double(0, 6.2832); + } + Point p = construct_point(k, + (a + b * cos(v)) * cos(u) + (noise == 0. ? 0. : rng.get_double(0, noise)), + (a + b * cos(v)) * sin(u) + (noise == 0. ? 0. : rng.get_double(0, noise)), + b * sin(v) * cos(u / 2) + (noise == 0. ? 0. : rng.get_double(0, noise)), + b * sin(v) * sin(u / 2) + (noise == 0. ? 0. : rng.get_double(0, noise))); + points.push_back(p); + ++i; + } + return points; +} + + +// a = big radius, b = small radius + +template +std::vector +generate_points_on_klein_bottle_variant_5D( + std::size_t num_points, double a, double b, bool uniform = false) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::FT FT; + Kernel k; + CGAL::Random rng; + + // if uniform + std::size_t num_lines = (std::size_t)sqrt(num_points); + + std::vector points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + FT u, v; + if (uniform) { + std::size_t k1 = i / num_lines; + std::size_t k2 = i % num_lines; + u = 6.2832 * k1 / num_lines; + v = 6.2832 * k2 / num_lines; + } else { + u = rng.get_double(0, 6.2832); + v = rng.get_double(0, 6.2832); + } + FT x1 = (a + b * cos(v)) * cos(u); + FT x2 = (a + b * cos(v)) * sin(u); + FT x3 = b * sin(v) * cos(u / 2); + FT x4 = b * sin(v) * sin(u / 2); + FT x5 = x1 + x2 + x3 + x4; + + Point p = construct_point(k, x1, x2, x3, x4, x5); + points.push_back(p); + ++i; + } + return points; +} + +} // namespace Gudhi + +#endif // RANDOM_POINT_GENERATORS_H_ diff --git a/include/gudhi/reader_utils.h b/include/gudhi/reader_utils.h index 899f9df6..97a87edd 100644 --- a/include/gudhi/reader_utils.h +++ b/include/gudhi/reader_utils.h @@ -2,9 +2,9 @@ * (Geometric Understanding in Higher Dimensions) is a generic C++ * library for computational topology. * - * Author(s): Clément Maria + * Author(s): Clement Maria, Pawel Dlotko * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,18 +30,25 @@ #include #include #include -#include // for numeric_limits<> +#include // for numeric_limits #include #include +#include // for pair + +// Keep this file tag for Doxygen to parse the code, otherwise, functions are not documented. +// It is required for global functions and variables. + +/** @file + * @brief This file includes common file reader for GUDHI + */ /** - * \brief Read a set of points to turn it - * into a vector< vector > by filling points + * @brief Read a set of points to turn it into a vector< vector > by filling points. * - * File format: 1 point per line - * X11 X12 ... X1d - * X21 X22 ... X2d - * etc + * File format: 1 point per line
+ * X11 X12 ... X1d
+ * X21 X22 ... X2d
+ * etc
*/ inline void read_points(std::string file_name, std::vector< std::vector< double > > & points) { std::ifstream in_file(file_name.c_str(), std::ios::in); @@ -66,23 +73,29 @@ inline void read_points(std::string file_name, std::vector< std::vector< double } /** - * \brief Read a graph from a file. + * @brief Read a graph from a file. + * + * \tparam Graph_t Type for the return graph. Must be constructible from iterators on pairs of Vertex_handle + * \tparam Filtration_value Type for the value of the read filtration + * \tparam Vertex_handle Type for the value of the read vertices * - * File format: 1 simplex per line - * Dim1 X11 X12 ... X1d Fil1 - * Dim2 X21 X22 ... X2d Fil2 - * etc + * File format: 1 simplex per line
+ * Dim1 X11 X12 ... X1d Fil1
+ * Dim2 X21 X22 ... X2d Fil2
+ * etc
* * The vertices must be labeled from 0 to n-1. * Every simplex must appear exactly once. * Simplices of dimension more than 1 are ignored. */ -inline Graph_t read_graph(std::string file_name) { +template< typename Graph_t, typename Filtration_value, typename Vertex_handle > +Graph_t read_graph(std::string file_name) { std::ifstream in_(file_name.c_str(), std::ios::in); if (!in_.is_open()) { std::cerr << "Unable to open file " << file_name << std::endl; } + typedef std::pair< Vertex_handle, Vertex_handle > Edge_t; std::vector< Edge_t > edges; std::vector< Filtration_value > edges_fil; std::map< Vertex_handle, Filtration_value > vertices; @@ -130,7 +143,7 @@ inline Graph_t read_graph(std::string file_name) { Graph_t skel_graph(edges.begin(), edges.end(), edges_fil.begin(), vertices.size()); auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph); - boost::graph_traits::vertex_iterator vi, vi_end; + typename boost::graph_traits::vertex_iterator vi, vi_end; auto v_it = vertices.begin(); for (std::tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi, ++v_it) { boost::put(vertex_prop, *vi, v_it->second); @@ -140,12 +153,12 @@ inline Graph_t read_graph(std::string file_name) { } /** - * \brief Read a face from a file. + * @brief Read a face from a file. * - * File format: 1 simplex per line - * Dim1 X11 X12 ... X1d Fil1 - * Dim2 X21 X22 ... X2d Fil2 - * etc + * File format: 1 simplex per line
+ * Dim1 X11 X12 ... X1d Fil1
+ * Dim2 X21 X22 ... X2d Fil2
+ * etc
* * The vertices must be labeled from 0 to n-1. * Every simplex must appear exactly once. @@ -166,18 +179,16 @@ bool read_simplex(std::istream & in_, std::vector< Vertex_handle > & simplex, Fi } /** - * \brief Read a hasse simplex from a file. - * - * File format: 1 simplex per line - * Dim1 k11 k12 ... k1Dim1 Fil1 - * Dim2 k21 k22 ... k2Dim2 Fil2 - * etc - * - * The key of a simplex is its position in the filtration order - * and also the number of its row in the file. - * Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the - * filtration has dimension Dimi, filtration value fil1 and simplices with - * key ki1 ... kiDimi in its boundary.*/ + * @brief Read a hasse simplex from a file. + * + * File format: 1 simplex per line
+ * Dim1 k11 k12 ... k1Dim1 Fil1
+ * Dim2 k21 k22 ... k2Dim2 Fil2
+ * etc
+ * + * The key of a simplex is its position in the filtration order and also the number of its row in the file. + * Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the filtration has dimension Dimi, filtration value + * fil1 and simplices with key ki1 ... kiDimi in its boundary.*/ template< typename Simplex_key, typename Filtration_value > bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundary, Filtration_value & fil) { int dim; @@ -195,4 +206,93 @@ bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundar return true; } +/** + * @brief Read a lower triangular distance matrix from a csv file. We assume that the .csv store the whole + * (square) matrix. + * + * @author Pawel Dlotko + * + * Square matrix file format:
+ * 0;D12;...;D1j
+ * D21;0;...;D2j
+ * ...
+ * Dj1;Dj2;...;0
+ * + * lower matrix file format:
+ * 0
+ * D21;
+ * D31;D32;
+ * ...
+ * Dj1;Dj2;...;Dj(j-1);
+ * + **/ +template< typename Filtration_value > +std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from_csv_file(const std::string& filename, + const char separator = ';') { +#ifdef DEBUG_TRACES + std::cout << "Using procedure read_lower_triangular_matrix_from_csv_file \n"; +#endif // DEBUG_TRACES + std::vector< std::vector< Filtration_value > > result; + std::ifstream in; + in.open(filename.c_str()); + if (!in.is_open()) { + return result; + } + + std::string line; + + // the first line is emtpy, so we ignore it: + std::getline(in, line); + std::vector< Filtration_value > values_in_this_line; + result.push_back(values_in_this_line); + + int number_of_line = 0; + + // first, read the file line by line to a string: + while (std::getline(in, line)) { + // if line is empty, break + if (line.size() == 0) + break; + + // if the last element of a string is comma: + if (line[ line.size() - 1 ] == separator) { + // then shrink the string by one + line.pop_back(); + } + + // replace all commas with spaces + std::replace(line.begin(), line.end(), separator, ' '); + + // put the new line to a stream + std::istringstream iss(line); + // and now read the doubles. + + int number_of_entry = 0; + std::vector< Filtration_value > values_in_this_line; + while (iss.good()) { + double entry; + iss >> entry; + if (number_of_entry <= number_of_line) { + values_in_this_line.push_back(entry); + } + ++number_of_entry; + } + if (!values_in_this_line.empty())result.push_back(values_in_this_line); + ++number_of_line; + } + in.close(); + +#ifdef DEBUG_TRACES + std::cerr << "Here is the matrix we read : \n"; + for (size_t i = 0; i != result.size(); ++i) { + for (size_t j = 0; j != result[i].size(); ++j) { + std::cerr << result[i][j] << " "; + } + std::cerr << std::endl; + } +#endif // DEBUG_TRACES + + return result; +} // read_lower_triangular_matrix_from_csv_file + #endif // READER_UTILS_H_ diff --git a/include/gudhi/sparsify_point_set.h b/include/gudhi/sparsify_point_set.h new file mode 100644 index 00000000..507f8c79 --- /dev/null +++ b/include/gudhi/sparsify_point_set.h @@ -0,0 +1,113 @@ +/* This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): Clement Jamin + * + * Copyright (C) 2016 INRIA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SPARSIFY_POINT_SET_H_ +#define SPARSIFY_POINT_SET_H_ + +#include +#ifdef GUDHI_SUBSAMPLING_PROFILING +#include +#endif + +#include +#include + +namespace Gudhi { + +namespace subsampling { + +/** + * \ingroup subsampling + * \brief Outputs a subset of the input points so that the + * squared distance between any two points + * is greater than or equal to `min_squared_dist`. + * + * \tparam Kernel must be a model of the SearchTraits + * concept, such as the CGAL::Epick_d class, which + * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't. + * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access + * via `operator[]` and the points should be stored contiguously in memory. + * \tparam OutputIterator Output iterator whose value type is Kernel::Point_d. + * + * @param[in] k A kernel object. + * @param[in] input_pts Const reference to the input points. + * @param[in] min_squared_dist Minimum squared distance separating the output points. + * @param[out] output_it The output iterator. + */ +template +void +sparsify_point_set( + const Kernel &k, Point_range const& input_pts, + typename Kernel::FT min_squared_dist, + OutputIterator output_it) { + typedef typename Gudhi::spatial_searching::Kd_tree_search< + Kernel, Point_range> Points_ds; + +#ifdef GUDHI_SUBSAMPLING_PROFILING + Gudhi::Clock t; +#endif + + Points_ds points_ds(input_pts); + + std::vector dropped_points(input_pts.size(), false); + + // Parse the input points, and add them if they are not too close to + // the other points + std::size_t pt_idx = 0; + for (typename Point_range::const_iterator it_pt = input_pts.begin(); + it_pt != input_pts.end(); + ++it_pt, ++pt_idx) { + if (dropped_points[pt_idx]) + continue; + + *output_it++ = *it_pt; + + auto ins_range = points_ds.query_incremental_nearest_neighbors(*it_pt); + + // If another point Q is closer that min_squared_dist, mark Q to be dropped + for (auto const& neighbor : ins_range) { + std::size_t neighbor_point_idx = neighbor.first; + // If the neighbor is too close, we drop the neighbor + if (neighbor.second < min_squared_dist) { + // N.B.: If neighbor_point_idx < pt_idx, + // dropped_points[neighbor_point_idx] is already true but adding a + // test doesn't make things faster, so why bother? + dropped_points[neighbor_point_idx] = true; + } else { + break; + } + } + } + +#ifdef GUDHI_SUBSAMPLING_PROFILING + t.end(); + std::cerr << "Point set sparsified in " << t.num_seconds() + << " seconds." << std::endl; +#endif +} + +} // namespace subsampling +} // namespace Gudhi + +#endif // SPARSIFY_POINT_SET_H_ diff --git a/include/gudhi_patches/Bottleneck_distance_CGAL_patches.txt b/include/gudhi_patches/Bottleneck_distance_CGAL_patches.txt new file mode 100644 index 00000000..a588d113 --- /dev/null +++ b/include/gudhi_patches/Bottleneck_distance_CGAL_patches.txt @@ -0,0 +1,3 @@ +CGAL/Kd_tree.h +CGAL/Kd_tree_node.h +CGAL/Orthogonal_incremental_neighbor_search.h diff --git a/include/gudhi_patches/CGAL/Convex_hull.h b/include/gudhi_patches/CGAL/Convex_hull.h new file mode 100644 index 00000000..a8f91bf8 --- /dev/null +++ b/include/gudhi_patches/CGAL/Convex_hull.h @@ -0,0 +1,56 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +/* RANDOM DESIGN IDEAS: +- Use a policy tag to choose for incremental with inserts only or + incremental with removals and inserts. + In the first case: use Triangulation for storage. + In the second case: use Delaunay ! + In this second case, we must keeps the points that are inserted in the hull, + as they may become part of the boundary later on, when some points are removed. +- Constructor with range argument uses quickhull. +*/ + +#ifndef CGAL_CONVEX_HULL_H +#define CGAL_CONVEX_HULL_H + +namespace CGAL { + +template < class CHTraits, class TDS_ = Default > +class Convex_hull +{ + typedef typename Maximal_dimension::type + Maximal_dimension_; + typedef typename Default::Get, + Triangulation_full_cell > + >::type TDS; + typedef Convex_hull Self; + + typedef typename CHTraits::Coaffine_orientation_d + Coaffine_orientation_d; + typedef typename CHTraits::Orientation_d Orientation_d; + +public: +}; + +} //namespace CGAL + +#endif // CGAL_CONVEX_HULL_H diff --git a/include/gudhi_patches/CGAL/Delaunay_triangulation.h b/include/gudhi_patches/CGAL/Delaunay_triangulation.h new file mode 100644 index 00000000..071cd184 --- /dev/null +++ b/include/gudhi_patches/CGAL/Delaunay_triangulation.h @@ -0,0 +1,933 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_DELAUNAY_COMPLEX_H +#define CGAL_DELAUNAY_COMPLEX_H + +#include +#include +#include +#include + +#include + +#include + +namespace CGAL { + +template< typename DCTraits, typename _TDS = Default > +class Delaunay_triangulation +: public Triangulation, + Triangulation_full_cell > + >::type > +{ + typedef typename DCTraits::Dimension Maximal_dimension_; + typedef typename Default::Get<_TDS, Triangulation_data_structure< + Maximal_dimension_, + Triangulation_vertex, + Triangulation_full_cell > + >::type TDS; + typedef Triangulation Base; + typedef Delaunay_triangulation Self; + + typedef typename DCTraits::Side_of_oriented_sphere_d + Side_of_oriented_sphere_d; + typedef typename DCTraits::Orientation_d Orientation_d; + +public: // PUBLIC NESTED TYPES + + typedef DCTraits Geom_traits; + typedef typename Base::Triangulation_ds Triangulation_ds; + + typedef typename Base::Vertex Vertex; + typedef typename Base::Full_cell Full_cell; + typedef typename Base::Facet Facet; + typedef typename Base::Face Face; + + typedef typename Base::Maximal_dimension Maximal_dimension; + typedef typename DCTraits::Point_d Point; + typedef typename DCTraits::Point_d Point_d; + + typedef typename Base::Vertex_handle Vertex_handle; + typedef typename Base::Vertex_iterator Vertex_iterator; + typedef typename Base::Vertex_const_handle Vertex_const_handle; + typedef typename Base::Vertex_const_iterator Vertex_const_iterator; + + typedef typename Base::Full_cell_handle Full_cell_handle; + typedef typename Base::Full_cell_iterator Full_cell_iterator; + typedef typename Base::Full_cell_const_handle Full_cell_const_handle; + typedef typename Base::Full_cell_const_iterator Full_cell_const_iterator; + typedef typename Base::Finite_full_cell_const_iterator + Finite_full_cell_const_iterator; + + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + + typedef typename Base::Locate_type Locate_type; + + //Tag to distinguish triangulations with weighted_points + typedef Tag_false Weighted_tag; + +protected: // DATA MEMBERS + + +public: + + using typename Base::Rotor; + using Base::maximal_dimension; + using Base::are_incident_full_cells_valid; + using Base::coaffine_orientation_predicate; + using Base::reset_flat_orientation; + using Base::current_dimension; + //using Base::star; + //using Base::incident_full_cells; + using Base::geom_traits; + using Base::index_of_covertex; + //using Base::index_of_second_covertex; + using Base::infinite_vertex; + using Base::rotate_rotor; + using Base::insert_in_hole; + using Base::insert_outside_convex_hull_1; + using Base::is_infinite; + using Base::locate; + using Base::points_begin; + using Base::set_neighbors; + using Base::new_full_cell; + using Base::number_of_vertices; + using Base::orientation; + using Base::tds; + using Base::reorient_full_cells; + using Base::full_cell; + using Base::full_cells_begin; + using Base::full_cells_end; + using Base::finite_full_cells_begin; + using Base::finite_full_cells_end; + using Base::vertices_begin; + using Base::vertices_end; + // using Base:: + +private: + //*** Side_of_oriented_subsphere_d *** + typedef typename Base::Flat_orientation_d Flat_orientation_d; + typedef typename Base::Construct_flat_orientation_d Construct_flat_orientation_d; + typedef typename DCTraits::In_flat_side_of_oriented_sphere_d In_flat_side_of_oriented_sphere_d; + // Wrapper + struct Side_of_oriented_subsphere_d + { + boost::optional* fop; + Construct_flat_orientation_d cfo; + In_flat_side_of_oriented_sphere_d ifsoos; + + Side_of_oriented_subsphere_d( + boost::optional& x, + Construct_flat_orientation_d const&y, + In_flat_side_of_oriented_sphere_d const&z) + : fop(&x), cfo(y), ifsoos(z) {} + + template + CGAL::Orientation operator()(Iter a, Iter b, const Point & p)const + { + if(!*fop) + *fop=cfo(a,b); + return ifsoos(fop->get(),a,b,p); + } + }; +public: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - CREATION / CONSTRUCTORS + + Delaunay_triangulation(int dim, const Geom_traits &k = Geom_traits()) + : Base(dim, k) + { + } + + // With this constructor, + // the user can specify a Flat_orientation_d object to be used for + // orienting simplices of a specific dimension + // (= preset_flat_orientation_.first) + // It it used by the dark triangulations created by DT::remove + Delaunay_triangulation( + int dim, + const std::pair &preset_flat_orientation, + const Geom_traits &k = Geom_traits()) + : Base(dim, preset_flat_orientation, k) + { + } + + ~Delaunay_triangulation() {} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ACCESS + + // Not Documented + Side_of_oriented_subsphere_d side_of_oriented_subsphere_predicate() const + { + return Side_of_oriented_subsphere_d ( + flat_orientation_, + geom_traits().construct_flat_orientation_d_object(), + geom_traits().in_flat_side_of_oriented_sphere_d_object() + ); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + + Full_cell_handle remove(Vertex_handle); + Full_cell_handle remove(const Point & p, Full_cell_handle hint = Full_cell_handle()) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, hint); + if( Base::ON_VERTEX == lt ) + { + return remove(s->vertex(f.index(0))); + } + return Full_cell_handle(); + } + + template< typename ForwardIterator > + void remove(ForwardIterator start, ForwardIterator end) + { + while( start != end ) + remove(*start++); + } + + // Not documented + void remove_decrease_dimension(Vertex_handle); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERTIONS + + template< typename ForwardIterator > + size_type insert(ForwardIterator start, ForwardIterator end) + { + size_type n = number_of_vertices(); + std::vector points(start, end); + spatial_sort(points.begin(), points.end(), geom_traits()); + Full_cell_handle hint; + for( typename std::vector::const_iterator p = points.begin(); p != points.end(); ++p ) + { + hint = insert(*p, hint)->full_cell(); + } + return number_of_vertices() - n; + } + Vertex_handle insert(const Point &, Locate_type, const Face &, const Facet &, Full_cell_handle); + Vertex_handle insert(const Point & p, Full_cell_handle start = Full_cell_handle()) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, start); + return insert(p, lt, f, ft, s); + } + Vertex_handle insert(const Point & p, Vertex_handle hint) + { + CGAL_assertion( Vertex_handle() != hint ); + return insert(p, hint->full_cell()); + } + Vertex_handle insert_outside_affine_hull(const Point &); + Vertex_handle insert_in_conflicting_cell(const Point &, Full_cell_handle); + +// - - - - - - - - - - - - - - - - - - - - - - - - - GATHERING CONFLICTING SIMPLICES + + bool is_in_conflict(const Point &, Full_cell_const_handle) const; + template< class OrientationPredicate > + Oriented_side perturbed_side_of_positive_sphere(const Point &, + Full_cell_const_handle, const OrientationPredicate &) const; + + template< typename OutputIterator > + Facet compute_conflict_zone(const Point &, Full_cell_handle, OutputIterator) const; + + template < typename OrientationPredicate, typename SideOfOrientedSpherePredicate > + class Conflict_predicate + { + const Self & dc_; + const Point & p_; + OrientationPredicate ori_; + SideOfOrientedSpherePredicate side_of_s_; + int cur_dim_; + public: + Conflict_predicate( + const Self & dc, + const Point & p, + const OrientationPredicate & ori, + const SideOfOrientedSpherePredicate & side) + : dc_(dc), p_(p), ori_(ori), side_of_s_(side), cur_dim_(dc.current_dimension()) {} + + inline + bool operator()(Full_cell_const_handle s) const + { + bool ok; + if( ! dc_.is_infinite(s) ) + { + Oriented_side side = side_of_s_(dc_.points_begin(s), dc_.points_begin(s) + cur_dim_ + 1, p_); + if( ON_POSITIVE_SIDE == side ) + ok = true; + else if( ON_NEGATIVE_SIDE == side ) + ok = false; + else + ok = ON_POSITIVE_SIDE == dc_.perturbed_side_of_positive_sphere(p_, s, ori_); + } + else + { + typedef typename Full_cell::Vertex_handle_const_iterator VHCI; + typedef Substitute_point_in_vertex_iterator F; + F spivi(dc_.infinite_vertex(), &p_); + + Orientation o = ori_( + boost::make_transform_iterator(s->vertices_begin(), spivi), + boost::make_transform_iterator(s->vertices_begin() + cur_dim_ + 1, + spivi)); + + if( POSITIVE == o ) + ok = true; + else if( o == NEGATIVE ) + ok = false; + else + ok = (*this)(s->neighbor( s->index( dc_.infinite_vertex() ) )); + } + return ok; + } + }; + + template < typename ConflictPredicate > + class Conflict_traversal_predicate + { + const Self & dc_; + const ConflictPredicate & pred_; + public: + Conflict_traversal_predicate(const Self & dc, const ConflictPredicate & pred) + : dc_(dc), pred_(pred) + {} + inline + bool operator()(const Facet & f) const + { + return pred_(dc_.full_cell(f)->neighbor(dc_.index_of_covertex(f))); + } + }; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + + bool is_valid(bool verbose = false, int level = 0) const; + +private: + // Some internal types to shorten notation + typedef typename Base::Coaffine_orientation_d Coaffine_orientation_d; + using Base::flat_orientation_; + typedef Conflict_predicate + Conflict_pred_in_subspace; + typedef Conflict_predicate + Conflict_pred_in_fullspace; + typedef Conflict_traversal_predicate + Conflict_traversal_pred_in_subspace; + typedef Conflict_traversal_predicate + Conflict_traversal_pred_in_fullspace; +}; + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +// FUNCTIONS THAT ARE MEMBER METHODS: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + +template< typename DCTraits, typename TDS > +typename Delaunay_triangulation::Full_cell_handle +Delaunay_triangulation +::remove( Vertex_handle v ) +{ + CGAL_precondition( ! is_infinite(v) ); + CGAL_expensive_precondition( is_vertex(v) ); + + // THE CASE cur_dim == 0 + if( 0 == current_dimension() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + else if( 1 == current_dimension() ) + { // THE CASE cur_dim == 1 + if( 2 == number_of_vertices() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + Full_cell_handle left = v->full_cell(); + if( 0 == left->index(v) ) + left = left->neighbor(1); + CGAL_assertion( 1 == left->index(v) ); + Full_cell_handle right = left->neighbor(0); + + tds().associate_vertex_with_full_cell(left, 1, right->vertex(1)); + set_neighbors(left, 0, right->neighbor(0), right->mirror_index(0)); + + tds().delete_vertex(v); + tds().delete_full_cell(right); + return left; + } + + // THE CASE cur_dim >= 2 + // Gather the finite vertices sharing an edge with |v| + typedef typename Base::template Full_cell_set Simplices; + Simplices simps; + std::back_insert_iterator out(simps); + tds().incident_full_cells(v, out); + typedef std::set Vertex_set; + Vertex_set verts; + Vertex_handle vh; + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + for( int i = 0; i <= current_dimension(); ++i ) + { + vh = (*it)->vertex(i); + if( is_infinite(vh) ) + continue; + if( vh == v ) + continue; + verts.insert(vh); + } + + // After gathering finite neighboring vertices, create their Dark Delaunay triangulation + typedef Triangulation_vertex Dark_vertex_base; + typedef Triangulation_full_cell > Dark_full_cell_base; + typedef Triangulation_data_structure Dark_tds; + typedef Delaunay_triangulation Dark_triangulation; + typedef typename Dark_triangulation::Face Dark_face; + typedef typename Dark_triangulation::Facet Dark_facet; + typedef typename Dark_triangulation::Vertex_handle Dark_v_handle; + typedef typename Dark_triangulation::Full_cell_handle Dark_s_handle; + + // If flat_orientation_ is defined, we give it the Dark triangulation + // so that the orientation it uses for "current_dimension()"-simplices is + // coherent with the global triangulation + Dark_triangulation dark_side( + maximal_dimension(), + flat_orientation_ ? + std::pair(current_dimension(), flat_orientation_.get_ptr()) + : std::pair((std::numeric_limits::max)(), (Flat_orientation_d*) NULL) ); + + Dark_s_handle dark_s; + Dark_v_handle dark_v; + typedef std::map Vertex_map; + Vertex_map light_to_dark; + typename Vertex_set::iterator vit = verts.begin(); + while( vit != verts.end() ) + { + dark_v = dark_side.insert((*vit)->point(), dark_s); + dark_s = dark_v->full_cell(); + dark_v->data() = *vit; + light_to_dark[*vit] = dark_v; + ++vit; + } + + if( dark_side.current_dimension() != current_dimension() ) + { + CGAL_assertion( dark_side.current_dimension() + 1 == current_dimension() ); + // Here, the finite neighbors of |v| span a affine subspace of + // dimension one less than the current dimension. Two cases are possible: + if( (size_type)(verts.size() + 1) == number_of_vertices() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + else + { // |v| is strictly outside the convex hull of the rest of the points. This is an + // easy case: first, modify the finite full_cells, then, delete the infinite ones. + // We don't even need the Dark triangulation. + Simplices infinite_simps; + { + Simplices finite_simps; + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + if( is_infinite(*it) ) + infinite_simps.push_back(*it); + else + finite_simps.push_back(*it); + simps.swap(finite_simps); + } // now, simps only contains finite simplices + // First, modify the finite full_cells: + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + { + int v_idx = (*it)->index(v); + tds().associate_vertex_with_full_cell(*it, v_idx, infinite_vertex()); + } + // Make the handles to infinite full cells searchable + infinite_simps.make_searchable(); + // Then, modify the neighboring relation + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + { + for( int i = 0; i <= current_dimension(); ++i ) + { + if (is_infinite((*it)->vertex(i))) + continue; + (*it)->vertex(i)->set_full_cell(*it); + Full_cell_handle n = (*it)->neighbor(i); + // Was |n| a finite full cell prior to removing |v| ? + if( ! infinite_simps.contains(n) ) + continue; + int n_idx = n->index(v); + set_neighbors(*it, i, n->neighbor(n_idx), n->neighbor(n_idx)->index(n)); + } + } + Full_cell_handle ret_s; + // Then, we delete the infinite full_cells + for( typename Simplices::iterator it = infinite_simps.begin(); it != infinite_simps.end(); ++it ) + tds().delete_full_cell(*it); + tds().delete_vertex(v); + return simps.front(); + } + } + else // From here on, dark_side.current_dimension() == current_dimension() + { + dark_side.infinite_vertex()->data() = infinite_vertex(); + light_to_dark[infinite_vertex()] = dark_side.infinite_vertex(); + } + + // Now, compute the conflict zone of v->point() in + // the dark side. This is precisely the set of full_cells + // that we have to glue back into the light side. + Dark_face dark_f(dark_side.maximal_dimension()); + Dark_facet dark_ft; + typename Dark_triangulation::Locate_type lt; + dark_s = dark_side.locate(v->point(), lt, dark_f, dark_ft); + CGAL_assertion( lt != Dark_triangulation::ON_VERTEX + && lt != Dark_triangulation::OUTSIDE_AFFINE_HULL ); + + // |ret_s| is the full_cell that we return + Dark_s_handle dark_ret_s = dark_s; + Full_cell_handle ret_s; + + typedef typename Base::template Full_cell_set Dark_full_cells; + Dark_full_cells conflict_zone; + std::back_insert_iterator dark_out(conflict_zone); + + dark_ft = dark_side.compute_conflict_zone(v->point(), dark_s, dark_out); + // Make the dark simplices in the conflict zone searchable + conflict_zone.make_searchable(); + + // THE FOLLOWING SHOULD MAYBE GO IN TDS. + // Here is the plan: + // 1. Pick any Facet from boundary of the light zone + // 2. Find corresponding Facet on boundary of dark zone + // 3. stitch. + + // 1. Build a facet on the boudary of the light zone: + Full_cell_handle light_s = *simps.begin(); + Facet light_ft(light_s, light_s->index(v)); + + // 2. Find corresponding Dark_facet on boundary of the dark zone + Dark_full_cells dark_incident_s; + for( int i = 0; i <= current_dimension(); ++i ) + { + if( index_of_covertex(light_ft) == i ) + continue; + Dark_v_handle dark_v = light_to_dark[full_cell(light_ft)->vertex(i)]; + dark_incident_s.clear(); + dark_out = std::back_inserter(dark_incident_s); + dark_side.tds().incident_full_cells(dark_v, dark_out); + for( typename Dark_full_cells::iterator it = dark_incident_s.begin(); it != dark_incident_s.end(); ++it ) + { + (*it)->data().count_ += 1; + } + } + + for( typename Dark_full_cells::iterator it = dark_incident_s.begin(); it != dark_incident_s.end(); ++it ) + { + if( current_dimension() != (*it)->data().count_ ) + continue; + if( ! conflict_zone.contains(*it) ) + continue; + // We found a full_cell incident to the dark facet corresponding to the light facet |light_ft| + int ft_idx = 0; + while( light_s->has_vertex( (*it)->vertex(ft_idx)->data() ) ) + ++ft_idx; + dark_ft = Dark_facet(*it, ft_idx); + break; + } + // Pre-3. Now, we are ready to traverse both boundary and do the stiching. + + // But first, we create the new full_cells in the light triangulation, + // with as much adjacency information as possible. + + // Create new full_cells with vertices + for( typename Dark_full_cells::iterator it = conflict_zone.begin(); it != conflict_zone.end(); ++it ) + { + Full_cell_handle new_s = new_full_cell(); + (*it)->data().light_copy_ = new_s; + for( int i = 0; i <= current_dimension(); ++i ) + tds().associate_vertex_with_full_cell(new_s, i, (*it)->vertex(i)->data()); + if( dark_ret_s == *it ) + ret_s = new_s; + } + + // Setup adjacencies inside the hole + for( typename Dark_full_cells::iterator it = conflict_zone.begin(); it != conflict_zone.end(); ++it ) + { + Full_cell_handle new_s = (*it)->data().light_copy_; + for( int i = 0; i <= current_dimension(); ++i ) + if( conflict_zone.contains((*it)->neighbor(i)) ) + tds().set_neighbors(new_s, i, (*it)->neighbor(i)->data().light_copy_, (*it)->mirror_index(i)); + } + + // 3. Stitch + simps.make_searchable(); + typedef std::queue > Queue; + Queue q; + q.push(std::make_pair(light_ft, dark_ft)); + dark_s = dark_side.full_cell(dark_ft); + int dark_i = dark_side.index_of_covertex(dark_ft); + // mark dark_ft as visited: + // TODO try by marking with Dark_v_handle (vertex) + dark_s->neighbor(dark_i)->set_neighbor(dark_s->mirror_index(dark_i), Dark_s_handle()); + while( ! q.empty() ) + { + std::pair p = q.front(); + q.pop(); + light_ft = p.first; + dark_ft = p.second; + light_s = full_cell(light_ft); + int light_i = index_of_covertex(light_ft); + dark_s = dark_side.full_cell(dark_ft); + int dark_i = dark_side.index_of_covertex(dark_ft); + Full_cell_handle light_n = light_s->neighbor(light_i); + set_neighbors(dark_s->data().light_copy_, dark_i, light_n, light_s->mirror_index(light_i)); + for( int di = 0; di <= current_dimension(); ++di ) + { + if( di == dark_i ) + continue; + int li = light_s->index(dark_s->vertex(di)->data()); + Rotor light_r(light_s, li, light_i); + typename Dark_triangulation::Rotor dark_r(dark_s, di, dark_i); + + while (simps.contains(cpp11::get<0>(light_r)->neighbor(cpp11::get<1>(light_r)))) + light_r = rotate_rotor(light_r); + + while (conflict_zone.contains(cpp11::get<0>(dark_r)->neighbor(cpp11::get<1>(dark_r)))) + dark_r = dark_side.rotate_rotor(dark_r); + + Dark_s_handle dark_ns = cpp11::get<0>(dark_r); + int dark_ni = cpp11::get<1>(dark_r); + Full_cell_handle light_ns = cpp11::get<0>(light_r); + int light_ni = cpp11::get<1>(light_r); + // mark dark_r as visited: + // TODO try by marking with Dark_v_handle (vertex) + Dark_s_handle outside = dark_ns->neighbor(dark_ni); + Dark_v_handle mirror = dark_ns->mirror_vertex(dark_ni, current_dimension()); + int dn = outside->index(mirror); + if( Dark_s_handle() == outside->neighbor(dn) ) + continue; + outside->set_neighbor(dn, Dark_s_handle()); + q.push(std::make_pair(Facet(light_ns, light_ni), Dark_facet(dark_ns, dark_ni))); + } + } + tds().delete_full_cells(simps.begin(), simps.end()); + tds().delete_vertex(v); + return ret_s; +} + +template< typename DCTraits, typename TDS > +void +Delaunay_triangulation +::remove_decrease_dimension(Vertex_handle v) +{ + CGAL_precondition( current_dimension() >= 0 ); + tds().remove_decrease_dimension(v, infinite_vertex()); + // reset the predicates: + reset_flat_orientation(); + if( 1 <= current_dimension() ) + { + Full_cell_handle inf_v_cell = infinite_vertex()->full_cell(); + int inf_v_index = inf_v_cell->index(infinite_vertex()); + Full_cell_handle s = inf_v_cell->neighbor(inf_v_index); + Orientation o = orientation(s); + CGAL_assertion( ZERO != o ); + if( NEGATIVE == o ) + reorient_full_cells(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERTIONS + +template< typename DCTraits, typename TDS > +typename Delaunay_triangulation::Vertex_handle +Delaunay_triangulation +::insert(const Point & p, Locate_type lt, const Face & f, const Facet &, Full_cell_handle s) +{ + switch( lt ) + { + case Base::OUTSIDE_AFFINE_HULL: + return insert_outside_affine_hull(p); + break; + case Base::ON_VERTEX: + { + Vertex_handle v = s->vertex(f.index(0)); + v->set_point(p); + return v; + break; + } + default: + if( 1 == current_dimension() ) + { + if( Base::OUTSIDE_CONVEX_HULL == lt ) + { + return insert_outside_convex_hull_1(p, s); + } + Vertex_handle v = tds().insert_in_full_cell(s); + v->set_point(p); + return v; + } + else + return insert_in_conflicting_cell(p, s); + break; + } +} + +/* +[Undocumented function] + +Inserts the point `p` in the Delaunay triangulation. Returns a handle to the +(possibly newly created) vertex at that position. +\pre The point `p` +must lie outside the affine hull of the Delaunay triangulation. This implies that +`dt`.`current_dimension()` must be less than `dt`.`maximal_dimension()`. +*/ +template< typename DCTraits, typename TDS > +typename Delaunay_triangulation::Vertex_handle +Delaunay_triangulation +::insert_outside_affine_hull(const Point & p) +{ + // we don't use Base::insert_outside_affine_hull(...) because here, we + // also need to reset the side_of_oriented_subsphere functor. + CGAL_precondition( current_dimension() < maximal_dimension() ); + Vertex_handle v = tds().insert_increase_dimension(infinite_vertex()); + // reset the predicates: + reset_flat_orientation(); + v->set_point(p); + if( current_dimension() >= 1 ) + { + Full_cell_handle inf_v_cell = infinite_vertex()->full_cell(); + int inf_v_index = inf_v_cell->index(infinite_vertex()); + Full_cell_handle s = inf_v_cell->neighbor(inf_v_index); + Orientation o = orientation(s); + CGAL_assertion( ZERO != o ); + if( NEGATIVE == o ) + reorient_full_cells(); + + // We just inserted the second finite point and the right infinite + // cell is like : (inf_v, v), but we want it to be (v, inf_v) to be + // consistent with the rest of the cells + if (current_dimension() == 1) + { + // Is "inf_v_cell" the right infinite cell? + // Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices( + current_dimension() - 1, current_dimension()); + } + // Otherwise, let's find the right infinite cell + else + { + inf_v_cell = inf_v_cell->neighbor((inf_v_index + 1) % 2); + inf_v_index = inf_v_cell->index(infinite_vertex()); + // Is "inf_v_cell" the right infinite cell? + // Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices( + current_dimension() - 1, current_dimension()); + } + } + } + } + return v; +} + +/*! +[Undocumented function] + +Inserts the point `p` in the Delaunay triangulation. Returns a handle to the +(possibly newly created) vertex at that position. +\pre The point `p` must be in conflict with the full cell `c`. +*/ +template< typename DCTraits, typename TDS > +typename Delaunay_triangulation::Vertex_handle +Delaunay_triangulation +::insert_in_conflicting_cell(const Point & p, Full_cell_handle s) +{ + CGAL_precondition(is_in_conflict(p, s)); + + // for storing conflicting full_cells. + typedef std::vector Full_cell_h_vector; + CGAL_STATIC_THREAD_LOCAL_VARIABLE(Full_cell_h_vector,cs,0); + cs.clear(); + + std::back_insert_iterator out(cs); + Facet ft = compute_conflict_zone(p, s, out); + return insert_in_hole(p, cs.begin(), cs.end(), ft); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GATHERING CONFLICTING SIMPLICES + +// NOT DOCUMENTED +template< typename DCTraits, typename TDS > +template< typename OrientationPred > +Oriented_side +Delaunay_triangulation +::perturbed_side_of_positive_sphere(const Point & p, Full_cell_const_handle s, + const OrientationPred & ori) const +{ + CGAL_precondition_msg( ! is_infinite(s), "full cell must be finite"); + CGAL_expensive_precondition( POSITIVE == orientation(s) ); + typedef std::vector Points; + Points points(current_dimension() + 2); + int i(0); + for( ; i <= current_dimension(); ++i ) + points[i] = &(s->vertex(i)->point()); + points[i] = &p; + std::sort(points.begin(), points.end(), + internal::Triangulation::Compare_points_for_perturbation(*this)); + typename Points::const_reverse_iterator cut_pt = points.rbegin(); + Points test_points; + while( cut_pt != points.rend() ) + { + if( &p == *cut_pt ) + // because the full_cell "s" is assumed to be positively oriented + return ON_NEGATIVE_SIDE; // we consider |p| to lie outside the sphere + test_points.clear(); + typename Base::Point_const_iterator spit = points_begin(s); + int adjust_sign = -1; + for( i = 0; i < current_dimension(); ++i ) + { + if( &(*spit) == *cut_pt ) + { + ++spit; + adjust_sign = (((current_dimension() + i) % 2) == 0) ? -1 : +1; + } + test_points.push_back(&(*spit)); + ++spit; + } + test_points.push_back(&p); + + typedef typename CGAL::Iterator_project, + const Point &, const Point *> Point_pointer_iterator; + + Orientation ori_value = ori( + Point_pointer_iterator(test_points.begin()), + Point_pointer_iterator(test_points.end())); + + if( ZERO != ori_value ) + return Oriented_side( - adjust_sign * ori_value ); + + ++cut_pt; + } + CGAL_assertion(false); // we should never reach here + return ON_NEGATIVE_SIDE; +} + +template< typename DCTraits, typename TDS > +bool +Delaunay_triangulation +::is_in_conflict(const Point & p, Full_cell_const_handle s) const +{ + CGAL_precondition( 2 <= current_dimension() ); + if( current_dimension() < maximal_dimension() ) + { + Conflict_pred_in_subspace c(*this, p, coaffine_orientation_predicate(), side_of_oriented_subsphere_predicate()); + return c(s); + } + else + { + Orientation_d ori = geom_traits().orientation_d_object(); + Side_of_oriented_sphere_d side = geom_traits().side_of_oriented_sphere_d_object(); + Conflict_pred_in_fullspace c(*this, p, ori, side); + return c(s); + } +} + +template< typename DCTraits, typename TDS > +template< typename OutputIterator > +typename Delaunay_triangulation::Facet +Delaunay_triangulation +::compute_conflict_zone(const Point & p, Full_cell_handle s, OutputIterator out) const +{ + CGAL_precondition( 2 <= current_dimension() ); + if( current_dimension() < maximal_dimension() ) + { + Conflict_pred_in_subspace c(*this, p, coaffine_orientation_predicate(), side_of_oriented_subsphere_predicate()); + Conflict_traversal_pred_in_subspace tp(*this, c); + return tds().gather_full_cells(s, tp, out); + } + else + { + Orientation_d ori = geom_traits().orientation_d_object(); + Side_of_oriented_sphere_d side = geom_traits().side_of_oriented_sphere_d_object(); + Conflict_pred_in_fullspace c(*this, p, ori, side); + Conflict_traversal_pred_in_fullspace tp(*this, c); + return tds().gather_full_cells(s, tp, out); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + +template< typename DCTraits, typename TDS > +bool +Delaunay_triangulation +::is_valid(bool verbose, int level) const +{ + if (!Base::is_valid(verbose, level)) + return false; + + int dim = current_dimension(); + if (dim == maximal_dimension()) + { + for (Finite_full_cell_const_iterator cit = this->finite_full_cells_begin() ; + cit != this->finite_full_cells_end() ; ++cit ) + { + Full_cell_const_handle ch = cit.base(); + for(int i = 0; i < dim+1 ; ++i ) + { + // If the i-th neighbor is not an infinite cell + Vertex_handle opposite_vh = + ch->neighbor(i)->vertex(ch->neighbor(i)->index(ch)); + if (!is_infinite(opposite_vh)) + { + Side_of_oriented_sphere_d side = + geom_traits().side_of_oriented_sphere_d_object(); + if (side(Point_const_iterator(ch->vertices_begin()), + Point_const_iterator(ch->vertices_end()), + opposite_vh->point()) == ON_BOUNDED_SIDE) + { + if (verbose) + CGAL_warning_msg(false, "Non-empty sphere"); + return false; + } + } + } + } + } + return true; +} + + +} //namespace CGAL + +#endif // CGAL_DELAUNAY_COMPLEX_H diff --git a/include/gudhi_patches/CGAL/Epeck_d.h b/include/gudhi_patches/CGAL/Epeck_d.h new file mode 100644 index 00000000..52bce84c --- /dev/null +++ b/include/gudhi_patches/CGAL/Epeck_d.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_EPECK_D_H +#define CGAL_EPECK_D_H +#include +#include +#include +#include + + +namespace CGAL { +#define CGAL_BASE \ + Cartesian_base_d::Type, Dim> +template +struct Epeck_d_help1 +: CGAL_BASE +{ + CGAL_CONSTEXPR Epeck_d_help1(){} + CGAL_CONSTEXPR Epeck_d_help1(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE +#define CGAL_BASE \ + Kernel_d_interface< \ + Cartesian_wrap< \ + Epeck_d_help1, \ + Epeck_d > > +template +struct Epeck_d +: CGAL_BASE +{ + CGAL_CONSTEXPR Epeck_d(){} + CGAL_CONSTEXPR Epeck_d(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE +} +#endif diff --git a/include/gudhi_patches/CGAL/Epick_d.h b/include/gudhi_patches/CGAL/Epick_d.h new file mode 100644 index 00000000..64438539 --- /dev/null +++ b/include/gudhi_patches/CGAL/Epick_d.h @@ -0,0 +1,71 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_EPICK_D_H +#define CGAL_EPICK_D_H +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace CGAL { +#define CGAL_BASE \ + Cartesian_filter_K< \ + Cartesian_base_d, \ + Cartesian_base_d, \ + Cartesian_base_d::Type, Dim> \ + > +template +struct Epick_d_help1 +: CGAL_BASE +{ + CGAL_CONSTEXPR Epick_d_help1(){} + CGAL_CONSTEXPR Epick_d_help1(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE +#define CGAL_BASE \ + Cartesian_static_filters,Epick_d_help2 > +template +struct Epick_d_help2 +: CGAL_BASE +{ + CGAL_CONSTEXPR Epick_d_help2(){} + CGAL_CONSTEXPR Epick_d_help2(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE +#define CGAL_BASE \ + Kernel_d_interface< \ + Cartesian_wrap< \ + Epick_d_help2, \ + Epick_d > > +template +struct Epick_d +: CGAL_BASE +{ + CGAL_CONSTEXPR Epick_d(){} + CGAL_CONSTEXPR Epick_d(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE +} +#endif diff --git a/include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h b/include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h new file mode 100644 index 00000000..701f0820 --- /dev/null +++ b/include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h @@ -0,0 +1,320 @@ +// Copyright (c) 2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: $ +// $Id: $ +// +// Author(s) : Clement Jamin + + +#ifndef CGAL_TRIANGULATION_IO_H +#define CGAL_TRIANGULATION_IO_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace Triangulation_IO +{ +// TODO: test if the stream is binary or text? +template +int +output_point(std::ostream & os, const Traits &traits, const P & p) +{ + typedef typename Traits::Compute_coordinate_d Ccd; + const Ccd ccd = traits.compute_coordinate_d_object(); + const int dim = traits.point_dimension_d_object()(p); + if (dim > 0) + { + os << ccd(p, 0); + for (int i = 1 ; i < dim ; ++i) + os << " " << CGAL::to_double(ccd(p, i)); + } + return dim; +} + +// TODO: test if the stream is binary or text? +template +int +output_weighted_point(std::ostream & os, const Traits &traits, const P & p, + bool output_weight = true) +{ + typedef typename Traits::Compute_coordinate_d Ccd; + typename Traits::Construct_point_d cp = + traits.construct_point_d_object(); + typename Traits::Compute_weight_d pt_weight = traits.compute_weight_d_object(); + const Ccd ccd = traits.compute_coordinate_d_object(); + const int dim = traits.point_dimension_d_object()(p); + if (dim > 0) + { + output_point(os, traits, p); + if (output_weight) + os << " " << pt_weight(p); + } + return dim; +} + +// TODO: test if the stream is binary or text? +template +void +output_full_cell(std::ostream & os, const Traits &traits, const FCH & fch, + bool output_weights = false) +{ + typename FCH::value_type::Vertex_handle_iterator vit = fch->vertices_begin(); + for( ; vit != fch->vertices_end(); ++vit ) + { + int dim; + if (output_weights) + dim = output_weighted_point(os, traits, (*vit)->point()); + else + dim = output_point(os, traits, (*vit)->point()); + if (dim > 0) + os << std::endl; + } +} + +// TODO: test if the stream is binary or text? +/*template +void +input_point(std::istream & is, const Traits &traits, P & p) +{ + typedef typename Traits::FT FT; + std::vector coords; + + std::string line; + for(;;) + { + if (!std::getline(is, line)) + return is; + if (line != "") + break; + } + std::stringstream line_sstr(line); + FT temp; + while (line_sstr >> temp) + coords.push_back(temp); + + p = traits.construct_point_d_object()(coords.begin(), coords.end()); +}*/ + +} // namespace Triangulation_IO + +/////////////////////////////////////////////////////////////// +// TODO: replace these operator>> by an "input_point" function +/////////////////////////////////////////////////////////////// + +// TODO: test if the stream is binary or text? +template +std::istream & +operator>>(std::istream &is, typename Wrap::Point_d & p) +{ + typedef typename Wrap::Point_d P; + typedef typename K::FT FT; + std::vector coords; + + std::string line; + for(;;) + { + if (!std::getline(is, line)) + return is; + if (line != "") + break; + } + std::stringstream line_sstr(line); + FT temp; + while (line_sstr >> temp) + coords.push_back(temp); + + p = P(coords.begin(), coords.end()); + return is; +} + +// TODO: test if the stream is binary or text? +template +std::istream & +operator>>(std::istream &is, typename Wrap::Weighted_point_d & wp) +{ + typedef typename Wrap::Point_d P; + typedef typename Wrap::Weighted_point_d WP; + typedef typename K::FT FT; + + std::string line; + for(;;) + { + if (!std::getline(is, line)) + return is; + if (line != "") + break; + } + std::stringstream line_sstr(line); + FT temp; + std::vector coords; + while (line_sstr >> temp) + coords.push_back(temp); + + typename std::vector::iterator last = coords.end() - 1; + P p = P(coords.begin(), last); + wp = WP(p, *last); + + return is; +} + +// TODO: test if the stream is binary or text? +template +std::istream & +operator>>(std::istream &is, typename Wrap::Vector_d & v) +{ + typedef typename Wrap::Vector_d V; + typedef typename K::FT FT; + std::vector coords; + + std::string line; + for (;;) + { + if (!std::getline(is, line)) + return is; + if (line != "") + break; + } + std::stringstream line_sstr(line); + FT temp; + while (line_sstr >> temp) + coords.push_back(temp); + + v = V(coords.begin(), coords.end()); + return is; +} + +template < class GT, class TDS > +std::ostream & +export_triangulation_to_off(std::ostream & os, + const Triangulation & tr, + bool in_3D_export_surface_only = false) +{ + typedef Triangulation Tr; + typedef typename Tr::Vertex_const_handle Vertex_handle; + typedef typename Tr::Finite_vertex_const_iterator Finite_vertex_iterator; + typedef typename Tr::Finite_full_cell_const_iterator Finite_full_cell_iterator; + typedef typename Tr::Full_cell_const_iterator Full_cell_iterator; + typedef typename Tr::Full_cell Full_cell; + typedef typename Full_cell::Vertex_handle_const_iterator Full_cell_vertex_iterator; + + if (tr.maximal_dimension() < 2 || tr.maximal_dimension() > 3) + { + std::cerr << "Warning: export_tds_to_off => dimension should be 2 or 3."; + os << "Warning: export_tds_to_off => dimension should be 2 or 3."; + return os; + } + + size_t n = tr.number_of_vertices(); + + std::stringstream output; + + // write the vertices + std::map index_of_vertex; + int i = 0; + for(Finite_vertex_iterator it = tr.finite_vertices_begin(); + it != tr.finite_vertices_end(); ++it, ++i) + { + Triangulation_IO::output_point(output, tr.geom_traits(), it->point()); + if (tr.maximal_dimension() == 2) + output << " 0"; + output << std::endl; + index_of_vertex[it.base()] = i; + } + CGAL_assertion( i == n ); + + size_t number_of_triangles = 0; + if (tr.maximal_dimension() == 2) + { + for (Finite_full_cell_iterator fch = tr.finite_full_cells_begin() ; + fch != tr.finite_full_cells_end() ; ++fch) + { + output << "3 "; + for (Full_cell_vertex_iterator vit = fch->vertices_begin() ; + vit != fch->vertices_end() ; ++vit) + { + output << index_of_vertex[*vit] << " "; + } + output << std::endl; + ++number_of_triangles; + } + } + else if (tr.maximal_dimension() == 3) + { + if (in_3D_export_surface_only) + { + // Parse boundary facets + for (Full_cell_iterator fch = tr.full_cells_begin() ; + fch != tr.full_cells_end() ; ++fch) + { + if (tr.is_infinite(fch)) + { + output << "3 "; + for (Full_cell_vertex_iterator vit = fch->vertices_begin() ; + vit != fch->vertices_end() ; ++vit) + { + if (!tr.is_infinite(*vit)) + output << index_of_vertex[*vit] << " "; + } + output << std::endl; + ++number_of_triangles; + } + } + } + else + { + // Parse finite cells + for (Finite_full_cell_iterator fch = tr.finite_full_cells_begin() ; + fch != tr.finite_full_cells_end() ; ++fch) + { + output << "3 " + << index_of_vertex[fch->vertex(0)] << " " + << index_of_vertex[fch->vertex(1)] << " " + << index_of_vertex[fch->vertex(2)] + << std::endl; + output << "3 " + << index_of_vertex[fch->vertex(0)] << " " + << index_of_vertex[fch->vertex(2)] << " " + << index_of_vertex[fch->vertex(3)] + << std::endl; + output << "3 " + << index_of_vertex[fch->vertex(1)] << " " + << index_of_vertex[fch->vertex(2)] << " " + << index_of_vertex[fch->vertex(3)] + << std::endl; + output << "3 " + << index_of_vertex[fch->vertex(0)] << " " + << index_of_vertex[fch->vertex(1)] << " " + << index_of_vertex[fch->vertex(3)] + << std::endl; + number_of_triangles += 4; + } + } + } + + os << "OFF \n" + << n << " " + << number_of_triangles << " 0\n" + << output.str(); + + return os; +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_IO_H diff --git a/include/gudhi_patches/CGAL/Kd_tree.h b/include/gudhi_patches/CGAL/Kd_tree.h new file mode 100644 index 00000000..f085b0da --- /dev/null +++ b/include/gudhi_patches/CGAL/Kd_tree.h @@ -0,0 +1,582 @@ +// Copyright (c) 2002,2011,2014 Utrecht University (The Netherlands), Max-Planck-Institute Saarbruecken (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Hans Tangelder (), +// : Waqar Khan + +#ifndef CGAL_KD_TREE_H +#define CGAL_KD_TREE_H + +#include "Kd_tree_node.h" + +#include +#include +#include + +#include +#include +#include + + +#include +#include +#include + +#ifdef CGAL_HAS_THREADS +#include +#endif + +namespace CGAL { + +//template , class UseExtendedNode = Tag_true > +template , class UseExtendedNode = Tag_true > +class Kd_tree { + +public: + typedef SearchTraits Traits; + typedef Splitter_ Splitter; + typedef typename SearchTraits::Point_d Point_d; + typedef typename Splitter::Container Point_container; + + typedef typename SearchTraits::FT FT; + typedef Kd_tree_node Node; + typedef Kd_tree_leaf_node Leaf_node; + typedef Kd_tree_internal_node Internal_node; + typedef Kd_tree Tree; + typedef Kd_tree Self; + + typedef Node* Node_handle; + typedef const Node* Node_const_handle; + typedef Leaf_node* Leaf_node_handle; + typedef const Leaf_node* Leaf_node_const_handle; + typedef Internal_node* Internal_node_handle; + typedef const Internal_node* Internal_node_const_handle; + typedef typename std::vector::const_iterator Point_d_iterator; + typedef typename std::vector::const_iterator Point_d_const_iterator; + typedef typename Splitter::Separator Separator; + typedef typename std::vector::const_iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + + typedef typename std::vector::size_type size_type; + + typedef typename internal::Get_dimension_tag::Dimension D; + +private: + SearchTraits traits_; + Splitter split; + + + // wokaround for https://svn.boost.org/trac/boost/ticket/9332 +#if (_MSC_VER == 1800) && (BOOST_VERSION == 105500) + std::deque internal_nodes; + std::deque leaf_nodes; +#else + boost::container::deque internal_nodes; + boost::container::deque leaf_nodes; +#endif + + Node_handle tree_root; + + Kd_tree_rectangle* bbox; + std::vector pts; + + // Instead of storing the points in arrays in the Kd_tree_node + // we put all the data in a vector in the Kd_tree. + // and we only store an iterator range in the Kd_tree_node. + // + std::vector data; + + + #ifdef CGAL_HAS_THREADS + mutable CGAL_MUTEX building_mutex;//mutex used to protect const calls inducing build() + #endif + bool built_; + bool removed_; + + // protected copy constructor + Kd_tree(const Tree& tree) + : traits_(tree.traits_),built_(tree.built_) + {}; + + + // Instead of the recursive construction of the tree in the class Kd_tree_node + // we do this in the tree class. The advantage is that we then can optimize + // the allocation of the nodes. + + // The leaf node + Node_handle + create_leaf_node(Point_container& c) + { + Leaf_node node(true , static_cast(c.size())); + std::ptrdiff_t tmp = c.begin() - data.begin(); + node.data = pts.begin() + tmp; + + leaf_nodes.push_back(node); + Leaf_node_handle nh = &leaf_nodes.back(); + + + return nh; + } + + + // The internal node + + Node_handle + create_internal_node(Point_container& c, const Tag_true&) + { + return create_internal_node_use_extension(c); + } + + Node_handle + create_internal_node(Point_container& c, const Tag_false&) + { + return create_internal_node(c); + } + + + + // TODO: Similiar to the leaf_init function above, a part of the code should be + // moved to a the class Kd_tree_node. + // It is not proper yet, but the goal was to see if there is + // a potential performance gain through the Compact_container + Node_handle + create_internal_node_use_extension(Point_container& c) + { + Internal_node node(false); + internal_nodes.push_back(node); + Internal_node_handle nh = &internal_nodes.back(); + + Separator sep; + Point_container c_low(c.dimension(),traits_); + split(sep, c, c_low); + nh->set_separator(sep); + + int cd = nh->cutting_dimension(); + if(!c_low.empty()){ + nh->lower_low_val = c_low.tight_bounding_box().min_coord(cd); + nh->lower_high_val = c_low.tight_bounding_box().max_coord(cd); + } + else{ + nh->lower_low_val = nh->cutting_value(); + nh->lower_high_val = nh->cutting_value(); + } + if(!c.empty()){ + nh->upper_low_val = c.tight_bounding_box().min_coord(cd); + nh->upper_high_val = c.tight_bounding_box().max_coord(cd); + } + else{ + nh->upper_low_val = nh->cutting_value(); + nh->upper_high_val = nh->cutting_value(); + } + + CGAL_assertion(nh->cutting_value() >= nh->lower_low_val); + CGAL_assertion(nh->cutting_value() <= nh->upper_high_val); + + if (c_low.size() > split.bucket_size()){ + nh->lower_ch = create_internal_node_use_extension(c_low); + }else{ + nh->lower_ch = create_leaf_node(c_low); + } + if (c.size() > split.bucket_size()){ + nh->upper_ch = create_internal_node_use_extension(c); + }else{ + nh->upper_ch = create_leaf_node(c); + } + + + + + return nh; + } + + + // Note also that I duplicated the code to get rid if the if's for + // the boolean use_extension which was constant over the construction + Node_handle + create_internal_node(Point_container& c) + { + Internal_node node(false); + internal_nodes.push_back(node); + Internal_node_handle nh = &internal_nodes.back(); + Separator sep; + + Point_container c_low(c.dimension(),traits_); + split(sep, c, c_low); + nh->set_separator(sep); + + if (c_low.size() > split.bucket_size()){ + nh->lower_ch = create_internal_node(c_low); + }else{ + nh->lower_ch = create_leaf_node(c_low); + } + if (c.size() > split.bucket_size()){ + nh->upper_ch = create_internal_node(c); + }else{ + nh->upper_ch = create_leaf_node(c); + } + + + + return nh; + } + + + +public: + + Kd_tree(Splitter s = Splitter(),const SearchTraits traits=SearchTraits()) + : traits_(traits),split(s), built_(false), removed_(false) + {} + + template + Kd_tree(InputIterator first, InputIterator beyond, + Splitter s = Splitter(),const SearchTraits traits=SearchTraits()) + : traits_(traits),split(s), built_(false), removed_(false) + { + pts.insert(pts.end(), first, beyond); + } + + bool empty() const { + return pts.empty(); + } + + void + build() + { + // This function is not ready to be called when a tree already exists, one + // must call invalidate_built() first. + CGAL_assertion(!is_built()); + CGAL_assertion(!removed_); + const Point_d& p = *pts.begin(); + typename SearchTraits::Construct_cartesian_const_iterator_d ccci=traits_.construct_cartesian_const_iterator_d_object(); + int dim = static_cast(std::distance(ccci(p), ccci(p,0))); + + data.reserve(pts.size()); + for(unsigned int i = 0; i < pts.size(); i++){ + data.push_back(&pts[i]); + } + Point_container c(dim, data.begin(), data.end(),traits_); + bbox = new Kd_tree_rectangle(c.bounding_box()); + if (c.size() <= split.bucket_size()){ + tree_root = create_leaf_node(c); + }else { + tree_root = create_internal_node(c, UseExtendedNode()); + } + + //Reorder vector for spatial locality + std::vector ptstmp; + ptstmp.resize(pts.size()); + for (std::size_t i = 0; i < pts.size(); ++i){ + ptstmp[i] = *data[i]; + } + for(std::size_t i = 0; i < leaf_nodes.size(); ++i){ + std::ptrdiff_t tmp = leaf_nodes[i].begin() - pts.begin(); + leaf_nodes[i].data = ptstmp.begin() + tmp; + } + pts.swap(ptstmp); + + data.clear(); + + built_ = true; + } + +private: + //any call to this function is for the moment not threadsafe + void const_build() const { + #ifdef CGAL_HAS_THREADS + //this ensure that build() will be called once + CGAL_SCOPED_LOCK(building_mutex); + if(!is_built()) + #endif + const_cast(this)->build(); //THIS IS NOT THREADSAFE + } +public: + + bool is_built() const + { + return built_; + } + + void invalidate_built() + { + if(removed_){ + // Walk the tree to collect the remaining points. + // Writing directly to pts would likely work, but better be safe. + std::vector ptstmp; + //ptstmp.resize(root()->num_items()); + root()->tree_items(std::back_inserter(ptstmp)); + pts.swap(ptstmp); + removed_=false; + CGAL_assertion(is_built()); // the rest of the cleanup must happen + } + if(is_built()){ + internal_nodes.clear(); + leaf_nodes.clear(); + data.clear(); + delete bbox; + built_ = false; + } + } + + void clear() + { + invalidate_built(); + pts.clear(); + removed_ = false; + } + + void + insert(const Point_d& p) + { + invalidate_built(); + pts.push_back(p); + } + + template + void + insert(InputIterator first, InputIterator beyond) + { + invalidate_built(); + pts.insert(pts.end(),first, beyond); + } + +private: + struct Equal_by_coordinates { + SearchTraits const* traits; + Point_d const* pp; + bool operator()(Point_d const&q) const { + typename SearchTraits::Construct_cartesian_const_iterator_d ccci=traits->construct_cartesian_const_iterator_d_object(); + return std::equal(ccci(*pp), ccci(*pp,0), ccci(q)); + } + }; + Equal_by_coordinates equal_by_coordinates(Point_d const&p){ + Equal_by_coordinates ret = { &traits(), &p }; + return ret; + } + +public: + void + remove(const Point_d& p) + { + remove(p, equal_by_coordinates(p)); + } + + template + void + remove(const Point_d& p, Equal const& equal_to_p) + { +#if 0 + // This code could have quadratic runtime. + if (!is_built()) { + std::vector::iterator pi = std::find(pts.begin(), pts.end(), p); + // Precondition: the point must be there. + CGAL_assertion (pi != pts.end()); + pts.erase(pi); + return; + } +#endif + bool success = remove_(p, 0, false, 0, false, root(), equal_to_p); + CGAL_assertion(success); + + // Do not set the flag is the tree has been cleared. + if(is_built()) + removed_ |= success; + } +private: + template + bool remove_(const Point_d& p, + Internal_node_handle grandparent, bool parent_islower, + Internal_node_handle parent, bool islower, + Node_handle node, Equal const& equal_to_p) { + // Recurse to locate the point + if (!node->is_leaf()) { + Internal_node_handle newparent = static_cast(node); + // FIXME: This should be if(xcutting_dimension()] <= newparent->cutting_value()) { + if (remove_(p, parent, islower, newparent, true, newparent->lower(), equal_to_p)) + return true; + } + //if (traits().construct_cartesian_const_iterator_d_object()(p)[newparent->cutting_dimension()] >= newparent->cutting_value()) + return remove_(p, parent, islower, newparent, false, newparent->upper(), equal_to_p); + + CGAL_assertion(false); // Point was not found + } + + // Actual removal + Leaf_node_handle lnode = static_cast(node); + if (lnode->size() > 1) { + iterator pi = std::find_if(lnode->begin(), lnode->end(), equal_to_p); + // FIXME: we should ensure this never happens + if (pi == lnode->end()) return false; + iterator lasti = lnode->end() - 1; + if (pi != lasti) { + // Hack to get a non-const iterator + std::iter_swap(pts.begin()+(pi-pts.begin()), pts.begin()+(lasti-pts.begin())); + } + lnode->drop_last_point(); + } else if (!equal_to_p(*lnode->begin())) { + // FIXME: we should ensure this never happens + return false; + } else if (grandparent) { + Node_handle brother = islower ? parent->upper() : parent->lower(); + if (parent_islower) + grandparent->set_lower(brother); + else + grandparent->set_upper(brother); + } else if (parent) { + tree_root = islower ? parent->upper() : parent->lower(); + } else { + clear(); + } + return true; + } + +public: + //For efficiency; reserve the size of the points vectors in advance (if the number of points is already known). + void reserve(size_t size) + { + pts.reserve(size); + } + + //Get the capacity of the underlying points vector. + size_t capacity() + { + return pts.capacity(); + } + + + template + OutputIterator + search(OutputIterator it, const FuzzyQueryItem& q) const + { + if(! pts.empty()){ + + if(! is_built()){ + const_build(); + } + Kd_tree_rectangle b(*bbox); + return tree_root->search(it,q,b); + } + return it; + } + + + template + boost::optional + search_any_point(const FuzzyQueryItem& q) const + { + if(! pts.empty()){ + + if(! is_built()){ + const_build(); + } + Kd_tree_rectangle b(*bbox); + return tree_root->search_any_point(q,b); + } + return boost::none; + } + + + ~Kd_tree() { + if(is_built()){ + delete bbox; + } + } + + + const SearchTraits& + traits() const + { + return traits_; + } + + Node_const_handle + root() const + { + if(! is_built()){ + const_build(); + } + return tree_root; + } + + Node_handle + root() + { + if(! is_built()){ + build(); + } + return tree_root; + } + + void + print() const + { + if(! is_built()){ + const_build(); + } + root()->print(); + } + + const Kd_tree_rectangle& + bounding_box() const + { + if(! is_built()){ + const_build(); + } + return *bbox; + } + + const_iterator + begin() const + { + return pts.begin(); + } + + const_iterator + end() const + { + return pts.end(); + } + + size_type + size() const + { + return pts.size(); + } + + // Print statistics of the tree. + std::ostream& + statistics(std::ostream& s) const + { + if(! is_built()){ + const_build(); + } + s << "Tree statistics:" << std::endl; + s << "Number of items stored: " + << root()->num_items() << std::endl; + s << "Number of nodes: " + << root()->num_nodes() << std::endl; + s << " Tree depth: " << root()->depth() << std::endl; + return s; + } + + +}; + +} // namespace CGAL + +#endif // CGAL_KD_TREE_H diff --git a/include/gudhi_patches/CGAL/Kd_tree_node.h b/include/gudhi_patches/CGAL/Kd_tree_node.h new file mode 100644 index 00000000..909ee260 --- /dev/null +++ b/include/gudhi_patches/CGAL/Kd_tree_node.h @@ -0,0 +1,586 @@ +// Copyright (c) 2002,2011 Utrecht University (The Netherlands). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Authors : Hans Tangelder () + +#ifndef CGAL_KD_TREE_NODE_H +#define CGAL_KD_TREE_NODE_H + +#include "CGAL/Splitters.h" + +#include +#include + +namespace CGAL { + + template + class Kd_tree; + + template < class TreeTraits, class Splitter, class UseExtendedNode > + class Kd_tree_node { + + friend class Kd_tree; + + typedef typename Kd_tree::Node_handle Node_handle; + typedef typename Kd_tree::Node_const_handle Node_const_handle; + typedef typename Kd_tree::Internal_node_handle Internal_node_handle; + typedef typename Kd_tree::Internal_node_const_handle Internal_node_const_handle; + typedef typename Kd_tree::Leaf_node_handle Leaf_node_handle; + typedef typename Kd_tree::Leaf_node_const_handle Leaf_node_const_handle; + typedef typename TreeTraits::Point_d Point_d; + + typedef typename TreeTraits::FT FT; + typedef typename Kd_tree::Separator Separator; + typedef typename Kd_tree::Point_d_iterator Point_d_iterator; + typedef typename Kd_tree::iterator iterator; + typedef typename Kd_tree::D D; + + bool leaf; + + public : + Kd_tree_node(bool leaf_) + :leaf(leaf_){} + + bool is_leaf() const{ + return leaf; + } + + std::size_t + num_items() const + { + if (is_leaf()){ + Leaf_node_const_handle node = + static_cast(this); + return node->size(); + } + else { + Internal_node_const_handle node = + static_cast(this); + return node->lower()->num_items() + node->upper()->num_items(); + } + } + + std::size_t + num_nodes() const + { + if (is_leaf()) return 1; + else { + Internal_node_const_handle node = + static_cast(this); + return node->lower()->num_nodes() + node->upper()->num_nodes(); + } + } + + int + depth(const int current_max_depth) const + { + if (is_leaf()){ + return current_max_depth; + } + else { + Internal_node_const_handle node = + static_cast(this); + return + (std::max)( node->lower()->depth(current_max_depth + 1), + node->upper()->depth(current_max_depth + 1)); + } + } + + int + depth() const + { + return depth(1); + } + + template + OutputIterator + tree_items(OutputIterator it) const { + if (is_leaf()) { + Leaf_node_const_handle node = + static_cast(this); + if (node->size()>0) + for (iterator i=node->begin(); i != node->end(); i++) + {*it=*i; ++it;} + } + else { + Internal_node_const_handle node = + static_cast(this); + it=node->lower()->tree_items(it); + it=node->upper()->tree_items(it); + } + return it; + } + + + boost::optional + any_tree_item() const { + boost::optional result = boost::none; + if (is_leaf()) { + Leaf_node_const_handle node = + static_cast(this); + if (node->size()>0){ + return boost::make_optional(*(node->begin())); + } + } + else { + Internal_node_const_handle node = + static_cast(this); + result = node->lower()->any_tree_item(); + if(! result){ + result = node->upper()->any_tree_item(); + } + } + return result; + } + + + void + indent(int d) const + { + for(int i = 0; i < d; i++){ + std::cout << " "; + } + } + + + void + print(int d = 0) const + { + if (is_leaf()) { + Leaf_node_const_handle node = + static_cast(this); + indent(d); + std::cout << "leaf" << std::endl; + if (node->size()>0) + for (iterator i=node->begin(); i != node->end(); i++) + {indent(d);std::cout << *i << std::endl;} + } + else { + Internal_node_const_handle node = + static_cast(this); + indent(d); + std::cout << "lower tree" << std::endl; + node->lower()->print(d+1); + indent(d); + std::cout << "separator: dim = " << node->cutting_dimension() << " val = " << node->cutting_value() << std::endl; + indent(d); + std::cout << "upper tree" << std::endl; + node->upper()->print(d+1); + } + } + + + template + OutputIterator + search(OutputIterator it, const FuzzyQueryItem& q, + Kd_tree_rectangle& b) const + { + if (is_leaf()) { + Leaf_node_const_handle node = + static_cast(this); + if (node->size()>0) + for (iterator i=node->begin(); i != node->end(); i++) + if (q.contains(*i)) + {*it++=*i;} + } + else { + Internal_node_const_handle node = + static_cast(this); + // after splitting b denotes the lower part of b + Kd_tree_rectangle b_upper(b); + b.split(b_upper, node->cutting_dimension(), + node->cutting_value()); + + if (q.outer_range_contains(b)) + it=node->lower()->tree_items(it); + else + if (q.inner_range_intersects(b)) + it=node->lower()->search(it,q,b); + if (q.outer_range_contains(b_upper)) + it=node->upper()->tree_items(it); + else + if (q.inner_range_intersects(b_upper)) + it=node->upper()->search(it,q,b_upper); + }; + return it; + } + + + template + boost::optional + search_any_point(const FuzzyQueryItem& q, + Kd_tree_rectangle& b) const + { + boost::optional result = boost::none; + if (is_leaf()) { + Leaf_node_const_handle node = + static_cast(this); + if (node->size()>0) + for (iterator i=node->begin(); i != node->end(); i++) + if (q.contains(*i)) + { result = *i; break; } + } + else { + Internal_node_const_handle node = + static_cast(this); + // after splitting b denotes the lower part of b + Kd_tree_rectangle b_upper(b); + b.split(b_upper, node->cutting_dimension(), + node->cutting_value()); + + if (q.outer_range_contains(b)){ + result = node->lower()->any_tree_item(); + }else{ + if (q.inner_range_intersects(b)){ + result = node->lower()->search_any_point(q,b); + } + } + if(result){ + return result; + } + if (q.outer_range_contains(b_upper)){ + result = node->upper()->any_tree_item(); + }else{ + if (q.inner_range_intersects(b_upper)) + result = node->upper()->search_any_point(q,b_upper); + } + } + return result; + } + + }; + + + template < class TreeTraits, class Splitter, class UseExtendedNode > + class Kd_tree_leaf_node : public Kd_tree_node< TreeTraits, Splitter, UseExtendedNode >{ + + friend class Kd_tree; + + typedef typename Kd_tree::iterator iterator; + typedef Kd_tree_node< TreeTraits, Splitter, UseExtendedNode> Base; + typedef typename TreeTraits::Point_d Point_d; + + private: + + // private variables for leaf nodes + boost::int32_t n; // denotes number of items in a leaf node + iterator data; // iterator to data in leaf node + + + public: + + // default constructor + Kd_tree_leaf_node() + {} + + Kd_tree_leaf_node(bool leaf_ ) + : Base(leaf_) + {} + + Kd_tree_leaf_node(bool leaf_,unsigned int n_ ) + : Base(leaf_), n(n_) + {} + + // members for all nodes + + // members for leaf nodes only + inline + unsigned int + size() const + { + return n; + } + + inline + iterator + begin() const + { + return data; + } + + inline + iterator + end() const + { + return data + n; + } + + inline + void + drop_last_point() + { + --n; + } + + }; //leaf node + + + + template < class TreeTraits, class Splitter, class UseExtendedNode> + class Kd_tree_internal_node : public Kd_tree_node< TreeTraits, Splitter, UseExtendedNode >{ + + friend class Kd_tree; + + typedef Kd_tree_node< TreeTraits, Splitter, UseExtendedNode> Base; + typedef typename Kd_tree::Node_handle Node_handle; + typedef typename Kd_tree::Node_const_handle Node_const_handle; + + typedef typename TreeTraits::FT FT; + typedef typename Kd_tree::Separator Separator; + + private: + + // private variables for internal nodes + boost::int32_t cut_dim; + FT cut_val; + Node_handle lower_ch, upper_ch; + + + // private variables for extended internal nodes + FT upper_low_val; + FT upper_high_val; + FT lower_low_val; + FT lower_high_val; + + + public: + + // default constructor + Kd_tree_internal_node() + {} + + Kd_tree_internal_node(bool leaf_) + : Base(leaf_) + {} + + + // members for internal node and extended internal node + + inline + Node_const_handle + lower() const + { + return lower_ch; + } + + inline + Node_const_handle + upper() const + { + return upper_ch; + } + + inline + Node_handle + lower() + { + return lower_ch; + } + + inline + Node_handle + upper() + { + return upper_ch; + } + + inline + void + set_lower(Node_handle nh) + { + lower_ch = nh; + } + + inline + void + set_upper(Node_handle nh) + { + upper_ch = nh; + } + + // inline Separator& separator() {return sep; } + // use instead + inline + void set_separator(Separator& sep){ + cut_dim = sep.cutting_dimension(); + cut_val = sep.cutting_value(); + } + + inline + FT + cutting_value() const + { + return cut_val; + } + + inline + int + cutting_dimension() const + { + return cut_dim; + } + + // members for extended internal node only + inline + FT + upper_low_value() const + { + return upper_low_val; + } + + inline + FT + upper_high_value() const + { + return upper_high_val; + } + + inline + FT + lower_low_value() const + { + return lower_low_val; + } + + inline + FT + lower_high_value() const + { + return lower_high_val; + } + + /*Separator& + separator() + { + return Separator(cutting_dimension,cutting_value); + }*/ + + + };//internal node + + template < class TreeTraits, class Splitter> + class Kd_tree_internal_node : public Kd_tree_node< TreeTraits, Splitter, Tag_false >{ + + friend class Kd_tree; + + typedef Kd_tree_node< TreeTraits, Splitter, Tag_false> Base; + typedef typename Kd_tree::Node_handle Node_handle; + typedef typename Kd_tree::Node_const_handle Node_const_handle; + + typedef typename TreeTraits::FT FT; + typedef typename Kd_tree::Separator Separator; + + private: + + // private variables for internal nodes + boost::uint8_t cut_dim; + FT cut_val; + + Node_handle lower_ch, upper_ch; + + public: + + // default constructor + Kd_tree_internal_node() + {} + + Kd_tree_internal_node(bool leaf_) + : Base(leaf_) + {} + + + // members for internal node and extended internal node + + inline + Node_const_handle + lower() const + { + return lower_ch; + } + + inline + Node_const_handle + upper() const + { + return upper_ch; + } + + inline + Node_handle + lower() + { + return lower_ch; + } + + inline + Node_handle + upper() + { + return upper_ch; + } + + inline + void + set_lower(Node_handle nh) + { + lower_ch = nh; + } + + inline + void + set_upper(Node_handle nh) + { + upper_ch = nh; + } + + // inline Separator& separator() {return sep; } + // use instead + + inline + void set_separator(Separator& sep){ + cut_dim = sep.cutting_dimension(); + cut_val = sep.cutting_value(); + } + + inline + FT + cutting_value() const + { + return cut_val; + } + + inline + int + cutting_dimension() const + { + return cut_dim; + } + + /* Separator& + separator() + { + return Separator(cutting_dimension,cutting_value); + }*/ + + + };//internal node + + + +} // namespace CGAL +#endif // CGAL_KDTREE_NODE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h new file mode 100644 index 00000000..c13a9801 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h @@ -0,0 +1,177 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_LA_BASE_H +#define CGAL_KERNEL_D_CARTESIAN_LA_BASE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CGAL_EIGEN3_ENABLED +#include +#else +#error Eigen3 is required +#endif + +namespace CGAL { + +template < typename FT_, typename Dim_, +#if 1 + typename Vec_=Mix_vector, + Vector_vector, + FT_, Dim_>, +#elif 0 + typename Vec_=Array_vector, +#elif 0 + typename Vec_=Vector_vector, +#else + // Dangerous because of alignment. Ok on x86_64 without AVX. + typename Vec_=LA_eigen, +#endif + typename LA_=LA_eigen > + /* Default LA to Vec or to LA_eigen? */ +struct Cartesian_LA_base_d : public Dimension_base +{ + typedef Cartesian_LA_base_d Self; + typedef Cartesian_tag Rep_tag; + typedef Cartesian_tag Kernel_tag; + typedef Dim_ Default_ambient_dimension; + typedef Dim_ Max_ambient_dimension; + typedef Dim_ Dimension; + typedef LA_ LA; + template struct Ambient_dimension { typedef Dim_ type; }; + + typedef Vec_ LA_vector; + typedef typename LA_vector::Vector Point; + typedef typename LA_vector::Vector Vector; + typedef typename LA_vector::Vector Vector_; + typedef typename LA_vector::Construct_vector Constructor; + typedef typename LA_vector::Vector_const_iterator Point_cartesian_const_iterator; + typedef typename LA_vector::Vector_const_iterator Vector_cartesian_const_iterator; + + template struct Type {}; + template struct Type< Point_tag, D> { typedef Vector_ type; }; + template struct Type { typedef Vector_ type; }; + template struct Type< FT_tag, D> { typedef FT_ type; }; + template struct Type< RT_tag, D> { typedef FT_ type; }; + + typedef typeset + ::add::type + // FIXME: These have nothing to do here. + ::add::type + ::add::type + ::add::type + ::add::type + Object_list; + + typedef typeset< Point_cartesian_const_iterator_tag>::type + ::add::type + Iterator_list; + + template > struct Functor { + typedef Null_functor type; + }; + template struct Functor,D> { + typedef CartesianDVectorBase::Construct_LA_vector type; + }; + template struct Functor,D> { + typedef CartesianDVectorBase::Construct_LA_vector type; + }; + template struct Functor,D> { + typedef CartesianDVectorBase::Construct_cartesian_const_iterator type; + }; + template struct Functor,D> { + typedef CartesianDVectorBase::Construct_cartesian_const_iterator type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Sum_of_vectors type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Difference_of_vectors type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Opposite_vector type; + }; + template struct Functor::value + || !LA_vector::template Property::value> > { + typedef CartesianDVectorBase::Midpoint type; + }; + template struct Functor { + typedef CartesianDVectorBase::Compute_cartesian_coordinate type; + }; + template struct Functor { + typedef CartesianDVectorBase::Compute_cartesian_coordinate type; + }; + template struct Functor { + typedef CartesianDVectorBase::PV_dimension type; + }; + template struct Functor { + typedef CartesianDVectorBase::PV_dimension type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Orientation_of_vectors type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Orientation_of_points type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Scalar_product type; + }; + template struct Functor::value> > { + typedef CartesianDVectorBase::Squared_distance_to_origin_stored type; + }; + // Use integral_constant in case of failure, to distinguish from the previous one. + template struct Functor::value + || !LA_vector::template Property::value)*2> > { + typedef CartesianDVectorBase::Squared_distance_to_origin_via_dotprod type; + }; + template struct Functor { + typedef CartesianDVectorBase::Identity_functor type; + }; + template struct Functor { + typedef CartesianDVectorBase::Identity_functor type; + }; + + CGAL_CONSTEXPR Cartesian_LA_base_d(){} + CGAL_CONSTEXPR Cartesian_LA_base_d(int d):Dimension_base(d){} +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_LA_BASE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h new file mode 100644 index 00000000..871c463a --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h @@ -0,0 +1,344 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_CARTESIAN_LA_FUNCTORS_H +#define CGAL_CARTESIAN_LA_FUNCTORS_H + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace CartesianDVectorBase { +#ifndef CGAL_CXX11 +namespace internal { +template struct Construct_LA_vector_ { + struct Never_use {}; + void operator()(Never_use)const; +}; +#define CGAL_CODE(Z,N,_) template struct Construct_LA_vector_ > { \ + typedef typename R::Constructor Constructor; \ + typedef typename Get_type::type RT; \ + typedef typename R::Vector_ result_type; \ + result_type operator() \ + (BOOST_PP_ENUM_PARAMS(N,RT const& t)) const { \ + return typename Constructor::Values()(BOOST_PP_ENUM_PARAMS(N,t)); \ + } \ + result_type operator() \ + (BOOST_PP_ENUM_PARAMS(BOOST_PP_INC(N),RT const& t)) const { \ + return typename Constructor::Values_divide()(t##N,BOOST_PP_ENUM_PARAMS(N,t)); \ + } \ + }; +BOOST_PP_REPEAT_FROM_TO(2, 11, CGAL_CODE, _ ) +#undef CGAL_CODE +} +#endif + +template struct Construct_LA_vector +: private Store_kernel +#ifndef CGAL_CXX11 +, public internal::Construct_LA_vector_ +#endif +{ + //CGAL_FUNCTOR_INIT_IGNORE(Construct_LA_vector) + CGAL_FUNCTOR_INIT_STORE(Construct_LA_vector) + typedef R_ R; + typedef typename R::Constructor Constructor; + typedef typename Get_type::type RT; + typedef typename Get_type::type FT; + typedef typename R::Vector_ result_type; + typedef typename R_::Default_ambient_dimension Dimension; + result_type operator()(int d)const{ + CGAL_assertion(check_dimension_eq(d,this->kernel().dimension())); + return typename Constructor::Dimension()(d); + } + result_type operator()()const{ + return typename Constructor::Dimension()((std::max)(0,this->kernel().dimension())); + } + result_type operator()(int d, Zero_ const&)const{ + CGAL_assertion(check_dimension_eq(d,this->kernel().dimension())); + return typename Constructor::Dimension()(d); + } + result_type operator()(Zero_ const&)const{ + // Makes no sense for an unknown dimension. + return typename Constructor::Dimension()(this->kernel().dimension()); + } + result_type operator()(result_type const& v)const{ + return v; + } +#ifdef CGAL_CXX11 + result_type operator()(result_type&& v)const{ + return std::move(v); + } +#endif +#ifdef CGAL_CXX11 + template + typename std::enable_if::value && + boost::is_same, Dimension>::value, + result_type>::type + operator()(U&&...u)const{ + return typename Constructor::Values()(std::forward(u)...); + } + //template::value>::type,class=typename std::enable_if<(sizeof...(U)==static_dim+1)>::type,class=void> + template + typename std::enable_if::value && + boost::is_same, Dimension>::value, + result_type>::type + operator()(U&&...u)const{ + return Apply_to_last_then_rest()(typename Constructor::Values_divide(),std::forward(u)...); + } +#else + using internal::Construct_LA_vector_::operator(); +#endif + template inline + typename boost::enable_if,result_type>::type operator() + (Iter f,Iter g,Cartesian_tag t)const + { + return this->operator()((int)std::distance(f,g),f,g,t); + } + template inline + typename boost::enable_if,result_type>::type operator() + (int d,Iter f,Iter g,Cartesian_tag)const + { + CGAL_assertion(d==std::distance(f,g)); + CGAL_assertion(check_dimension_eq(d,this->kernel().dimension())); + return typename Constructor::Iterator()(d,f,g); + } + template inline + typename boost::enable_if,result_type>::type operator() + (Iter f,Iter g,Homogeneous_tag)const + { + --g; + return this->operator()((int)std::distance(f,g),f,g,*g); + } + template inline + typename boost::enable_if,result_type>::type operator() + (int d,Iter f,Iter g,Homogeneous_tag)const + { + --g; + return this->operator()(d,f,g,*g); + } + template inline + typename boost::enable_if,result_type>::type operator() + (Iter f,Iter g)const + { + // Shouldn't it try comparing dist(f,g) to the dimension if it is known? + return this->operator()(f,g,typename R::Rep_tag()); + } + template inline + typename boost::enable_if,result_type>::type operator() + (int d,Iter f,Iter g)const + { + return this->operator()(d,f,g,typename R::Rep_tag()); + } + + // Last homogeneous coordinate given separately + template inline + typename boost::enable_if,result_type>::type operator() + (int d,Iter f,Iter g,NT const&l)const + { + CGAL_assertion(d==std::distance(f,g)); + CGAL_assertion(check_dimension_eq(d,this->kernel().dimension())); + // RT? better be safe for now + return typename Constructor::Iterator()(d,CGAL::make_transforming_iterator(f,Divide(l)),CGAL::make_transforming_iterator(g,Divide(l))); + } + template inline + typename boost::enable_if,result_type>::type operator() + (Iter f,Iter g,NT const&l)const + { + return this->operator()((int)std::distance(f,g),f,g,l); + } +}; + +template struct Compute_cartesian_coordinate { + CGAL_FUNCTOR_INIT_IGNORE(Compute_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename R::Vector_ first_argument_type; + typedef int second_argument_type; + typedef Tag_true Is_exact; +#ifdef CGAL_CXX11 + typedef decltype(std::declval()[0]) result_type; +#else + typedef RT const& result_type; + // RT const& doesn't work with some LA (Eigen2 for instance) so we + // should use plain RT or find a way to detect this. +#endif + + result_type operator()(first_argument_type const& v,int i)const{ + return v[i]; + } +}; + +template struct Construct_cartesian_const_iterator { + CGAL_FUNCTOR_INIT_IGNORE(Construct_cartesian_const_iterator) + typedef R_ R; + typedef typename R::Vector_ argument_type; + typedef typename R::LA_vector S_; + typedef typename R::Point_cartesian_const_iterator result_type; + // same as Vector + typedef Tag_true Is_exact; + + result_type operator()(argument_type const& v,Begin_tag)const{ + return S_::vector_begin(v); + } + result_type operator()(argument_type const& v,End_tag)const{ + return S_::vector_end(v); + } +}; + +template struct Midpoint { + CGAL_FUNCTOR_INIT_IGNORE(Midpoint) + typedef R_ R; + typedef typename Get_type::type first_argument_type; + typedef typename Get_type::type second_argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return (a+b)/2; + } +}; + +template struct Sum_of_vectors { + CGAL_FUNCTOR_INIT_IGNORE(Sum_of_vectors) + typedef R_ R; + typedef typename Get_type::type first_argument_type; + typedef typename Get_type::type second_argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return a+b; + } +}; + +template struct Difference_of_vectors { + CGAL_FUNCTOR_INIT_IGNORE(Difference_of_vectors) + typedef R_ R; + typedef typename Get_type::type first_argument_type; + typedef typename Get_type::type second_argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return a-b; + } +}; + +template struct Opposite_vector { + CGAL_FUNCTOR_INIT_IGNORE(Opposite_vector) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_type::type argument_type; + + result_type operator()(result_type const& v)const{ + return -v; + } +}; + +template struct Scalar_product { + CGAL_FUNCTOR_INIT_IGNORE(Scalar_product) + typedef R_ R; + typedef typename R::LA_vector LA; + typedef typename Get_type::type result_type; + typedef typename Get_type::type first_argument_type; + typedef typename Get_type::type second_argument_type; + + result_type operator()(first_argument_type const& a, second_argument_type const& b)const{ + return LA::dot_product(a,b); + } +}; + +template struct Squared_distance_to_origin_stored { + CGAL_FUNCTOR_INIT_IGNORE(Squared_distance_to_origin_stored) + typedef R_ R; + typedef typename R::LA_vector LA; + typedef typename Get_type::type result_type; + typedef typename Get_type::type argument_type; + + result_type operator()(argument_type const& a)const{ + return LA::squared_norm(a); + } +}; + +template struct Squared_distance_to_origin_via_dotprod { + CGAL_FUNCTOR_INIT_IGNORE(Squared_distance_to_origin_via_dotprod) + typedef R_ R; + typedef typename R::LA_vector LA; + typedef typename Get_type::type result_type; + typedef typename Get_type::type argument_type; + + result_type operator()(argument_type const& a)const{ + return LA::dot_product(a,a); + } +}; + +template struct Orientation_of_vectors { + CGAL_FUNCTOR_INIT_IGNORE(Orientation_of_vectors) + typedef R_ R; + typedef typename R::Vector_cartesian_const_iterator first_argument_type; + typedef typename R::Vector_cartesian_const_iterator second_argument_type; + typedef typename Get_type::type result_type; + typedef typename R::LA_vector LA; + + template + result_type operator()(Iter const& f, Iter const& e) const { + return LA::determinant_of_iterators_to_vectors(f,e); + } +}; + +template struct Orientation_of_points { + CGAL_FUNCTOR_INIT_IGNORE(Orientation_of_points) + typedef R_ R; + typedef typename R::Point_cartesian_const_iterator first_argument_type; + typedef typename R::Point_cartesian_const_iterator second_argument_type; + typedef typename Get_type::type result_type; + typedef typename R::LA_vector LA; + + template + result_type operator()(Iter const& f, Iter const& e) const { + return LA::determinant_of_iterators_to_points(f,e); + } +}; + +template struct PV_dimension { + CGAL_FUNCTOR_INIT_IGNORE(PV_dimension) + typedef R_ R; + typedef typename R::Vector_ argument_type; + typedef int result_type; + typedef typename R::LA_vector LA; + typedef Tag_true Is_exact; + + template + result_type operator()(T const& v) const { + return LA::size_of_vector(v); + } +}; + +template struct Identity_functor { + CGAL_FUNCTOR_INIT_IGNORE(Identity_functor) + template + T const& operator()(T const&t) const { return t; } +}; + +} +} // namespace CGAL +#endif // CGAL_CARTESIAN_LA_FUNCTORS_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h new file mode 100644 index 00000000..641bf8ae --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_BASE_H +#define CGAL_KERNEL_D_CARTESIAN_BASE_H + +#include +#include +#include + +namespace CGAL { +#define CGAL_BASE \ + Cartesian_LA_base_d< FT_, Dim_ > +template < typename FT_, typename Dim_, typename Derived_=Default> +struct Cartesian_base_d : public CGAL_BASE +{ + CGAL_CONSTEXPR Cartesian_base_d(){} + CGAL_CONSTEXPR Cartesian_base_d(int d):CGAL_BASE(d){} +}; +#undef CGAL_BASE + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_BASE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h new file mode 100644 index 00000000..e09c72d0 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h @@ -0,0 +1,117 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_CHANGE_FT_H +#define CGAL_KERNEL_D_CARTESIAN_CHANGE_FT_H + +#include +#include +#include +#include + +namespace CGAL { + +template < typename Base_, typename FT_, typename LA_=CGAL::LA_eigen > +struct Cartesian_change_FT_base : public + Base_ +{ + CGAL_CONSTEXPR Cartesian_change_FT_base(){} + CGAL_CONSTEXPR Cartesian_change_FT_base(int d):Base_(d){} + + typedef Cartesian_change_FT_base Self; + typedef Base_ Kernel_base; + typedef LA_ LA; + + template struct Type : Inherit_type {}; + template struct Type { typedef FT_ type; }; + template struct Type { typedef FT_ type; }; + + typedef NT_converter::type,FT_> FT_converter; + typedef transforming_iterator Point_cartesian_const_iterator; + typedef transforming_iterator Vector_cartesian_const_iterator; + //FIXME: use Iterator_list! + /* + template::value_tag,FT_tag>::value> + struct Iterator : Get_type {}; + template struct Iterator { + typedef transforming_iterator::type> type; + }; + */ + + template + struct Construct_cartesian_const_iterator_ { + typedef typename Get_functor::type Functor_base; + Construct_cartesian_const_iterator_(){} + Construct_cartesian_const_iterator_(Self const&r):f(r){} + Functor_base f; + typedef Type_ result_type; + template + result_type operator()(T const& v, Begin_tag)const{ + return make_transforming_iterator(f(v,Begin_tag()),FT_converter()); + } + template + result_type operator()(T const& v, End_tag)const{ + return make_transforming_iterator(f(v,End_tag()),FT_converter()); + } + }; + typedef Construct_cartesian_const_iterator_,Point_cartesian_const_iterator> Construct_point_cartesian_const_iterator; + typedef Construct_cartesian_const_iterator_,Vector_cartesian_const_iterator> Construct_vector_cartesian_const_iterator; + + template + struct Compute_cartesian_coordinate { + typedef typename Get_functor::type Functor_base; + Compute_cartesian_coordinate(){} + Compute_cartesian_coordinate(Self const&r):f(r){} + Functor_base f; + typedef FT_ result_type; + template + result_type operator()(Obj_ const& v,int i)const{ + return FT_converter()(f(v,i)); + } + }; + + template::type> struct Functor : + Inherit_functor { }; + template struct Functor { }; + template struct Functor { }; + template struct Functor { + typedef Compute_cartesian_coordinate type; + }; + template struct Functor { + typedef Compute_cartesian_coordinate type; + }; + template struct Functor,D,Construct_iterator_tag> { + typedef Construct_point_cartesian_const_iterator type; + }; + template struct Functor,D,Construct_iterator_tag> { + typedef Construct_vector_cartesian_const_iterator type; + }; +}; + +template < typename Base_, typename FT_> +struct Cartesian_change_FT : public + Cartesian_change_FT_base +{ + CGAL_CONSTEXPR Cartesian_change_FT(){} + CGAL_CONSTEXPR Cartesian_change_FT(int d):Cartesian_change_FT_base(d){} +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_CHANGE_FT_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h new file mode 100644 index 00000000..ef8921db --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_COMPLETE_H +#define CGAL_KERNEL_D_CARTESIAN_COMPLETE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // CGAL_KERNEL_D_CARTESIAN_COMPLETE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h new file mode 100644 index 00000000..179e97bf --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h @@ -0,0 +1,79 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_FILTER_K_H +#define CGAL_KERNEL_D_CARTESIAN_FILTER_K_H + +#include +#include +#include +#include +#include + +namespace CGAL { + +template < typename Base_, typename AK_, typename EK_ > +struct Cartesian_filter_K : public Base_, + private Store_kernel, private Store_kernel2 +{ + CGAL_CONSTEXPR Cartesian_filter_K(){} + CGAL_CONSTEXPR Cartesian_filter_K(int d):Base_(d){} + //FIXME: or do we want an instance of AK and EK belonging to this kernel, + //instead of a reference to external ones? + CGAL_CONSTEXPR Cartesian_filter_K(AK_ const&a,EK_ const&b):Base_(),Store_kernel(a),Store_kernel2(b){} + CGAL_CONSTEXPR Cartesian_filter_K(int d,AK_ const&a,EK_ const&b):Base_(d),Store_kernel(a),Store_kernel2(b){} + typedef Base_ Kernel_base; + typedef AK_ AK; + typedef EK_ EK; + typedef typename Store_kernel::reference_type AK_rt; + AK_rt approximate_kernel()const{return this->kernel();} + typedef typename Store_kernel2::reference2_type EK_rt; + EK_rt exact_kernel()const{return this->kernel2();} + + // MSVC is too dumb to perform the empty base optimization. + typedef boost::mpl::and_< + internal::Do_not_store_kernel, + internal::Do_not_store_kernel, + internal::Do_not_store_kernel > Do_not_store_kernel; + + //TODO: C2A/C2E could be able to convert *this into this->kernel() or this->kernel2(). + typedef KernelD_converter C2A; + typedef KernelD_converter C2E; + + // fix the types + // TODO: only fix some types, based on some criterion? + template struct Type : Get_type {}; + + template::type> struct Functor : + Inherit_functor {}; + template struct Functor { + typedef typename Get_functor::type AP; + typedef typename Get_functor::type EP; + typedef Filtered_predicate2 type; + }; +// TODO: +// template struct Functor : +// Kernel_base::template Functor {}; +// TODO: +// detect when Less_cartesian_coordinate doesn't need filtering +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_FILTER_K_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h new file mode 100644 index 00000000..c390a55c --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h @@ -0,0 +1,93 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H +#define CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H + +#include +#include +#include + +namespace CGAL { + +template < typename Base_ > +struct Cartesian_filter_NT : public Base_ +{ + CGAL_CONSTEXPR Cartesian_filter_NT(){} + CGAL_CONSTEXPR Cartesian_filter_NT(int d):Base_(d){} + typedef Base_ Kernel_base; + typedef Cartesian_change_FT K1; + typedef typename internal::Exact_field_selector::type>::Type Exact_nt; + typedef Cartesian_change_FT K2; + + template::type> struct Functor : + Inherit_functor {}; + template struct Functor { + struct type { + //TODO: use compression (derive from a compressed_pair?) + typedef typename Get_functor::type P1; P1 p1; + typedef typename Get_functor::type P2; P2 p2; + typedef typename P2::result_type result_type; + type(){} + type(Cartesian_filter_NT const&k):p1(reinterpret_cast(k)),p2(reinterpret_cast(k)){} + //FIXME: if predicate's constructor takes a kernel as argument, how do we translate that? reinterpret_cast is really ugly and possibly unsafe. + +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + { + Protect_FPU_rounding p; + try { + typename P1::result_type res=p1(u...); // don't forward as u may be reused + if(is_certain(res)) return get_certain(res); + } catch (Uncertain_conversion_exception) {} + } + return p2(std::forward(u)...); + } +#else + result_type operator()()const{ // does it make sense to have 0 argument? + { + Protect_FPU_rounding p; + try { + typename P1::result_type res=p1(); + if(is_certain(res)) return get_certain(res); + } catch (Uncertain_conversion_exception) {} + } + return p2(); + } +#define CGAL_CODE(Z,N,_) template result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t))const{ \ + { \ + Protect_FPU_rounding p; \ + try { \ + typename P1::result_type res=p1(BOOST_PP_ENUM_PARAMS(N,t)); \ + if(is_certain(res)) return get_certain(res); \ + } catch (Uncertain_conversion_exception) {} \ + } \ + return p2(BOOST_PP_ENUM_PARAMS(N,t)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + +#endif + }; + }; +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h new file mode 100644 index 00000000..179f7319 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_CARTESIAN_PER_DIM_H +#define CGAL_KD_CARTESIAN_PER_DIM_H +#include +#include +#include + +// Should probably disappear. + +namespace CGAL { +template +struct Cartesian_per_dimension : public R_ {}; +} + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h new file mode 100644 index 00000000..693e962a --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h @@ -0,0 +1,95 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_CARTESIAN_STATIC_FILTERS_H +#define CGAL_KD_CARTESIAN_STATIC_FILTERS_H +#include +#include +#include // bug, should be included by the next one +#include +#include + +namespace CGAL { +namespace SFA { // static filter adapter +// Note that this would be quite a bit simpler without stateful kernels +template struct Orientation_of_points_2 : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points_2) + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename Get_type::type FT; + typedef typename Get_functor::type CC; + typedef typename Get_functor::type Orientation_base; + // TODO: Move this out for easy reuse + struct Adapter { + struct Point_2 { + R_ const&r; CC const&c; Point const& p; + Point_2(R_ const&r_, CC const&c_, Point const&p_):r(r_),c(c_),p(p_){} + // use result_of instead? + typename CC::result_type x()const{return c(p,0);} + typename CC::result_type y()const{return c(p,1);} + }; + struct Vector_2 {}; + struct Circle_2 {}; + struct Orientation_2 { + typedef typename Orientation_of_points_2::result_type result_type; + result_type operator()(Point_2 const&A, Point_2 const&B, Point_2 const&C)const{ + Point const* t[3]={&A.p,&B.p,&C.p}; + return Orientation_base(A.r)(make_transforming_iterator(t+0),make_transforming_iterator(t+3)); + } + }; + }; + template result_type operator()(Iter f, Iter CGAL_assertion_code(e))const{ + CC c(this->kernel()); + Point const& A=*f; + Point const& B=*++f; + Point const& C=*++f; + CGAL_assertion(++f==e); + typedef typename Adapter::Point_2 P; + return typename internal::Static_filters_predicates::Orientation_2()(P(this->kernel(),c,A),P(this->kernel(),c,B),P(this->kernel(),c,C)); + } +}; +} + +template +struct Cartesian_static_filters : public R_ { + CGAL_CONSTEXPR Cartesian_static_filters(){} + CGAL_CONSTEXPR Cartesian_static_filters(int d):R_(d){} +}; + +template +struct Cartesian_static_filters, R_, Derived_> : public R_ { + CGAL_CONSTEXPR Cartesian_static_filters(){} + CGAL_CONSTEXPR Cartesian_static_filters(int d):R_(d){} + typedef Cartesian_static_filters, R_, Derived_> Self; + typedef typename Default::Get::type Derived; + template struct Functor : Inherit_functor {}; + template struct Functor { + typedef + //typename boost::mpl::if_ < + //boost::is_same, + //typename Get_functor::type, + SFA::Orientation_of_points_2 + // >::type + type; + }; +}; + +} + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h b/include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h new file mode 100644 index 00000000..43015d24 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h @@ -0,0 +1,330 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_COAFFINE_H +#define CGAL_KD_COAFFINE_H +#include +#include +#include +#include +#include + +namespace CGAL { +namespace CartesianDKernelFunctors { +struct Flat_orientation { + std::vector proj; + std::vector rest; + bool reverse; +}; + +// For debugging purposes +inline std::ostream& operator<< (std::ostream& o, Flat_orientation const& f) { + o << "Proj: "; + for(std::vector::const_iterator i=f.proj.begin(); + i!=f.proj.end(); ++i) + o << *i << ' '; + o << "\nRest: "; + for(std::vector::const_iterator i=f.rest.begin(); + i!=f.rest.end(); ++i) + o << *i << ' '; + o << "\nInv: " << f.reverse; + return o << '\n'; +} + +namespace internal { +namespace coaffine { +template +inline void debug_matrix(std::ostream& o, Mat const&mat) { + for(int i=0;i struct Construct_flat_orientation : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_flat_orientation) + typedef R_ R; + typedef typename Get_type::type FT; + typedef typename Get_type::type Point; + typedef typename Increment_dimension::type Dplusone; + typedef typename R::LA::template Rebind_dimension::Other LA; + typedef typename LA::Square_matrix Matrix; + typedef typename Get_functor::type CCC; + typedef typename Get_functor::type PD; + typedef Flat_orientation result_type; + + // This implementation is going to suck. Maybe we should push the + // functionality into LA. And we should check (in debug mode) that + // the points are affinely independent. + template + result_type operator()(Iter f, Iter e)const{ + Iter f_save = f; + PD pd (this->kernel()); + CCC ccc (this->kernel()); + int dim = pd(*f); + Matrix coord (dim+1, dim+1); // use distance(f,e)? This matrix doesn't need to be square. + int col = 0; + Flat_orientation o; + std::vector& proj=o.proj; + std::vector& rest=o.rest; rest.reserve(dim+1); + for(int i=0; i p; + try + { + // No forward here, the arguments may still be needed + Ares res = ap(c2a(args)...); + if (is_certain(res)) + return get_certain(res); + } + catch (Uncertain_conversion_exception) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding p(CGAL_FE_TONEAREST); + return ep(c2e(std::forward(args))...); + } +#else + +#define CGAL_VAR(Z,N,C) C(a##N) +#define CGAL_CODE(Z,N,_) \ + template \ + result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, A, const& a)) const \ + { \ + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); \ + { \ + Protect_FPU_rounding p; \ + try \ + { \ + Ares res = ap(BOOST_PP_ENUM(N,CGAL_VAR,c2a)); \ + if (is_certain(res)) \ + return get_certain(res); \ + } \ + catch (Uncertain_conversion_exception) {} \ + } \ + CGAL_BRANCH_PROFILER_BRANCH(tmp); \ + Protect_FPU_rounding p(CGAL_FE_TONEAREST); \ + return ep(BOOST_PP_ENUM(N,CGAL_VAR,c2e)); \ + } + BOOST_PP_REPEAT_FROM_TO(1, 10, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR + +#endif +}; + +} //namespace CGAL + +#endif // CGAL_FILTERED_PREDICATE2_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h b/include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h new file mode 100644 index 00000000..a8896976 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h @@ -0,0 +1,199 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_CONVERTER_H +#define CGAL_KERNEL_D_CARTESIAN_CONVERTER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace internal { +// Reverses order, but that shouldn't matter. +template struct Map_taglist_to_typelist : + Map_taglist_to_typelist::type + ::template add::type> +{}; +template struct Map_taglist_to_typelist > : typeset<> {}; +} + +template > +struct Object_converter { + typedef Object result_type; + template + result_type operator()(Object const& o, F const& f) const { + typedef typename List::head H; + if (H const* ptr = object_cast(&o)) + return make_object(f(*ptr)); + else + return Object_converter()(o,f); + } +}; +template<> +struct Object_converter > { + typedef Object result_type; + template + result_type operator()(Object const&,F const&)const { + CGAL_error_msg("Cartesiand_converter is unable to determine what is wrapped in the Object"); + return Object(); + } +}; + + + //TODO: special case when K1==K2 (or they are very close?) +template +class KernelD_converter_ +: public KernelD_converter_ +{ + typedef typename List::head Tag_; + typedef typename List::tail Rest; + typedef KernelD_converter_ Base; + typedef typename Get_type::type K1_Obj; + typedef typename Get_type::type K2_Obj; + typedef typename Get_functor >::type K1_Conv; + typedef KO_converter KOC; + typedef CGAL_BOOSTD is_same no_converter; + typedef typename internal::Map_taglist_to_typelist::type::template contains duplicate; + + // Disable the conversion in some cases: + struct Do_not_use{}; + + // Explicit calls to boost::mpl functions to avoid parenthesis + // warning on some versions of GCC + typedef typename boost::mpl::if_ < + // If Point==Vector, keep only one conversion + boost::mpl::or_, + // For iterator objects, the default is make_transforming_iterator + boost::mpl::bool_<(iterator_tag_traits::is_iterator && no_converter::value)> >, + Do_not_use,K1_Obj>::type argument_type; + //typedef typename KOC::argument_type K1_Obj; + //typedef typename KOC::result_type K2_Obj; + public: + using Base::operator(); // don't use directly, just make it accessible to the next level + K2_Obj helper(K1_Obj const& o,CGAL_BOOSTD true_type)const{ + return KOC()(this->myself().kernel(),this->myself().kernel2(),this->myself(),o); + } + K2_Obj helper(K1_Obj const& o,CGAL_BOOSTD false_type)const{ + return K1_Conv(this->myself().kernel())(this->myself().kernel2(),this->myself(),o); + } + K2_Obj operator()(argument_type const& o)const{ + return helper(o,no_converter()); + } + template struct result:Base::template result{}; + template struct result {typedef K2_Obj type;}; +}; + +template +class KernelD_converter_ > { + public: + struct Do_not_use2{}; + void operator()(Do_not_use2)const{} + template struct result; + Final_& myself(){return *static_cast(this);} + Final_ const& myself()const{return *static_cast(this);} +}; + + +// TODO: use the intersection of Kn::Object_list. +template::type +//typeset::add::type/*::add::type*/ +> class KernelD_converter + : public Store_kernel, public Store_kernel2, + public KernelD_converter_,K1,K2,List_> +{ + typedef KernelD_converter Self; + typedef Self Final_; + typedef KernelD_converter_ Base; + typedef typename Get_type::type FT1; + typedef typename Get_type::type FT2; + typedef NT_converter NTc; + NTc c; // TODO: compressed storage as this is likely empty and the converter gets passed around (and stored in iterators) + + public: + KernelD_converter(){} + KernelD_converter(K1 const&a,K2 const&b):Store_kernel(a),Store_kernel2(b){} + + // For boost::result_of, used in transforming_iterator + template::value?42:0> struct result:Base::template result{}; + template struct result { + typedef transforming_iterator type; + }; + template struct result{typedef K2 type;}; + template struct result{typedef int type;}; + // Ideally the next 2 would come with Point_tag and Vector_tag, but that's hard... + template struct result{typedef Origin type;}; + template struct result{typedef Null_vector type;}; + template struct result{typedef Object type;}; + template struct result{typedef FT2 type;}; + + using Base::operator(); + typename Store_kernel2::reference2_type operator()(K1 const&)const{return this->kernel2();} + int operator()(int i)const{return i;} + Origin operator()(Origin const&o)const{return o;} + Null_vector operator()(Null_vector const&v)const{return v;} + FT2 operator()(FT1 const&x)const{return c(x);} + //RT2 operator()(typename First_if_different::Type const&x)const{return cr(x);} + + typename Get_type::type const& + operator()(typename Get_type::type const&o)const + { return o; } // Both kernels should have the same, returning a reference should warn if not. + + template + transforming_iterator,It>::type> + operator()(It const& it) const { + return make_transforming_iterator(it,*this); + } + + template + //TODO: use decltype in C++11 instead of result + std::vector::type> + operator()(const std::vector& v) const { + return std::vector::type>(operator()(v.begin()),operator()(v.begin())); + } + + //TODO: convert std::list and other containers? + + Object + operator()(const Object &obj) const + { + typedef typename internal::Map_taglist_to_typelist::type Possibilities; + //TODO: add Empty, vector, etc to the list. + return Object_converter()(obj,*this); + } + + //TODO: convert boost::variant + +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_CONVERTER_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h new file mode 100644 index 00000000..fa30dff0 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h @@ -0,0 +1,104 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_KERNEL_2_INTERFACE_H +#define CGAL_KD_KERNEL_2_INTERFACE_H + +#include +#include +#include +#include + + +namespace CGAL { +template struct Kernel_2_interface : public Base_ { + typedef Base_ Base; + typedef Kernel_2_interface Kernel; + typedef typename Get_type::type RT; + typedef typename Get_type::type FT; + typedef typename Get_type::type Boolean; + typedef typename Get_type::type Sign; + typedef typename Get_type::type Comparison_result; + typedef typename Get_type::type Orientation; + typedef typename Get_type::type Oriented_side; + typedef typename Get_type::type Bounded_side; + typedef typename Get_type::type Angle; + typedef typename Get_type::type Point_2; + typedef typename Get_type::type Vector_2; + typedef typename Get_type::type Segment_2; + typedef cpp0x::tuple Triangle_2; // triangulation insists... + template struct Help_2p_i { + typedef typename Get_functor::type LT; + typedef typename LT::result_type result_type; + LT lt; + Help_2p_i(Kernel const&k):lt(k){} + result_type operator()(Point_2 const&a, Point_2 const&b) { + return lt(a,b,i); + } + }; + typedef Help_2p_i Less_x_2; + typedef Help_2p_i Less_y_2; + typedef Help_2p_i Compare_x_2; + typedef Help_2p_i Compare_y_2; + struct Compare_distance_2 { + typedef typename Get_functor::type CD; + typedef typename CD::result_type result_type; + CD cd; + Compare_distance_2(Kernel const&k):cd(k){} + result_type operator()(Point_2 const&a, Point_2 const&b, Point_2 const&c) { + return cd(a,b,c); + } + result_type operator()(Point_2 const&a, Point_2 const&b, Point_2 const&c, Point_2 const&d) { + return cd(a,b,c,d); + } + }; + struct Orientation_2 { + typedef typename Get_functor::type O; + typedef typename O::result_type result_type; + O o; + Orientation_2(Kernel const&k):o(k){} + result_type operator()(Point_2 const&a, Point_2 const&b, Point_2 const&c) { + //return o(a,b,c); + Point_2 const* t[3]={&a,&b,&c}; + return o(make_transforming_iterator(t+0),make_transforming_iterator(t+3)); + + } + }; + struct Side_of_oriented_circle_2 { + typedef typename Get_functor::type SOS; + typedef typename SOS::result_type result_type; + SOS sos; + Side_of_oriented_circle_2(Kernel const&k):sos(k){} + result_type operator()(Point_2 const&a, Point_2 const&b, Point_2 const&c, Point_2 const&d) { + //return sos(a,b,c,d); + Point_2 const* t[4]={&a,&b,&c,&d}; + return sos(make_transforming_iterator(t+0),make_transforming_iterator(t+4)); + } + }; + Less_x_2 less_x_2_object()const{ return Less_x_2(*this); } + Less_y_2 less_y_2_object()const{ return Less_y_2(*this); } + Compare_x_2 compare_x_2_object()const{ return Compare_x_2(*this); } + Compare_y_2 compare_y_2_object()const{ return Compare_y_2(*this); } + Compare_distance_2 compare_distance_2_object()const{ return Compare_distance_2(*this); } + Orientation_2 orientation_2_object()const{ return Orientation_2(*this); } + Side_of_oriented_circle_2 side_of_oriented_circle_2_object()const{ return Side_of_oriented_circle_2(*this); } +}; +} + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h new file mode 100644 index 00000000..96076aa8 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h @@ -0,0 +1,102 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_KERNEL_3_INTERFACE_H +#define CGAL_KD_KERNEL_3_INTERFACE_H + +#include +#include +#include +#include + + +namespace CGAL { +template struct Kernel_3_interface : public Base_ { + typedef Base_ Base; + typedef Kernel_3_interface Kernel; + typedef typename Get_type::type RT; + typedef typename Get_type::type FT; + typedef typename Get_type::type Boolean; + typedef typename Get_type::type Sign; + typedef typename Get_type::type Comparison_result; + typedef typename Get_type::type Orientation; + typedef typename Get_type::type Oriented_side; + typedef typename Get_type::type Bounded_side; + typedef typename Get_type::type Angle; + typedef typename Get_type::type Point_3; + typedef typename Get_type::type Vector_3; + typedef typename Get_type::type Segment_3; + typedef cpp0x::tuple Triangle_3; // placeholder + typedef cpp0x::tuple Tetrahedron_3; // placeholder + struct Compare_xyz_3 { + typedef typename Get_functor::type CL; + typedef typename CL::result_type result_type; + CL cl; + Compare_xyz_3(Kernel const&k):cl(k){} + result_type operator()(Point_3 const&a, Point_3 const&b) { + return cl(a,b); + } + }; + struct Compare_distance_3 { + typedef typename Get_functor::type CD; + typedef typename CD::result_type result_type; + CD cd; + Compare_distance_3(Kernel const&k):cd(k){} + result_type operator()(Point_3 const&a, Point_3 const&b, Point_3 const&c) { + return cd(a,b,c); + } + result_type operator()(Point_3 const&a, Point_3 const&b, Point_3 const&c, Point_3 const&d) { + return cd(a,b,c,d); + } + }; + struct Orientation_3 { + typedef typename Get_functor::type O; + typedef typename O::result_type result_type; + O o; + Orientation_3(Kernel const&k):o(k){} + result_type operator()(Point_3 const&a, Point_3 const&b, Point_3 const&c, Point_3 const&d) { + //return o(a,b,c,d); + Point_3 const* t[4]={&a,&b,&c,&d}; + return o(make_transforming_iterator(t+0),make_transforming_iterator(t+4)); + + } + }; + struct Side_of_oriented_sphere_3 { + typedef typename Get_functor::type SOS; + typedef typename SOS::result_type result_type; + SOS sos; + Side_of_oriented_sphere_3(Kernel const&k):sos(k){} + result_type operator()(Point_3 const&a, Point_3 const&b, Point_3 const&c, Point_3 const&d, Point_3 const&e) { + //return sos(a,b,c,d); + Point_3 const* t[5]={&a,&b,&c,&d,&e}; + return sos(make_transforming_iterator(t+0),make_transforming_iterator(t+5)); + } + }; + + // I don't have the Coplanar predicates (yet) + + + Compare_xyz_3 compare_xyz_3_object()const{ return Compare_xyz_3(*this); } + Compare_distance_3 compare_distance_3_object()const{ return Compare_distance_3(*this); } + Orientation_3 orientation_3_object()const{ return Orientation_3(*this); } + Side_of_oriented_sphere_3 side_of_oriented_sphere_3_object()const{ return Side_of_oriented_sphere_3(*this); } +}; +} + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h new file mode 100644 index 00000000..dd888005 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h @@ -0,0 +1,298 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_KERNEL_D_INTERFACE_H +#define CGAL_KD_KERNEL_D_INTERFACE_H + +#include +#include +#include +#include + + +namespace CGAL { +template struct Kernel_d_interface : public Base_ { + CGAL_CONSTEXPR Kernel_d_interface(){} + CGAL_CONSTEXPR Kernel_d_interface(int d):Base_(d){} + + typedef Base_ Base; + typedef Kernel_d_interface Kernel; + typedef Base_ R_; // for the macros + typedef typename Get_type::type RT; + typedef typename Get_type::type FT; + typedef typename Get_type::type Boolean; + typedef typename Get_type::type Sign; + typedef typename Get_type::type Comparison_result; + typedef typename Get_type::type Orientation; + typedef typename Get_type::type Oriented_side; + typedef typename Get_type::type Bounded_side; + typedef typename Get_type::type Angle; + typedef typename Get_type::type Flat_orientation_d; + typedef typename Get_type::type Point_d; + typedef typename Get_type::type Vector_d; + typedef typename Get_type::type Segment_d; + typedef typename Get_type::type Sphere_d; + typedef typename Get_type::type Hyperplane_d; + typedef Vector_d Direction_d; + typedef typename Get_type::type Line_d; + typedef typename Get_type::type Ray_d; + typedef typename Get_type::type Iso_box_d; + typedef typename Get_type::type Aff_transformation_d; + typedef typename Get_type::type Weighted_point_d; + typedef typename Get_functor::type Compute_coordinate_d; + typedef typename Get_functor::type Compare_lexicographically_d; + typedef typename Get_functor::type Equal_d; + typedef typename Get_functor::type Less_lexicographically_d; + typedef typename Get_functor::type Less_or_equal_lexicographically_d; + // FIXME: and vectors? + typedef typename Get_functor::type Orientation_d; + typedef typename Get_functor::type Less_coordinate_d; + typedef typename Get_functor::type Point_dimension_d; + typedef typename Get_functor::type Side_of_oriented_sphere_d; + typedef typename Get_functor::type Power_side_of_power_sphere_d; + typedef typename Get_functor::type Power_center_d; + typedef typename Get_functor::type Power_distance_d; + typedef typename Get_functor::type Contained_in_affine_hull_d; + typedef typename Get_functor::type Construct_flat_orientation_d; + typedef typename Get_functor::type In_flat_orientation_d; + typedef typename Get_functor::type In_flat_side_of_oriented_sphere_d; + typedef typename Get_functor::type In_flat_power_side_of_power_sphere_d; + typedef typename Get_functor::type Point_to_vector_d; + typedef typename Get_functor::type Vector_to_point_d; + typedef typename Get_functor::type Translated_point_d; + typedef typename Get_functor::type Scaled_vector_d; + typedef typename Get_functor::type Difference_of_vectors_d; + typedef typename Get_functor::type Difference_of_points_d; + //typedef typename Get_functor >::type Construct_point_d; + struct Construct_point_d : private Store_kernel { + typedef Kernel R_; // for the macro + CGAL_FUNCTOR_INIT_STORE(Construct_point_d) + typedef typename Get_functor >::type CP; + typedef Point_d result_type; + Point_d operator()(Weighted_point_d const&wp)const{ + return typename Get_functor::type(this->kernel())(wp); + } +#ifdef CGAL_CXX11 + Point_d operator()(Weighted_point_d &wp)const{ + return typename Get_functor::type(this->kernel())(wp); + } + Point_d operator()(Weighted_point_d &&wp)const{ + return typename Get_functor::type(this->kernel())(std::move(wp)); + } + Point_d operator()(Weighted_point_d const&&wp)const{ + return typename Get_functor::type(this->kernel())(std::move(wp)); + } + template +# if __cplusplus >= 201402L + decltype(auto) +# else + Point_d +# endif + operator()(T&&...t)const{ + return CP(this->kernel())(std::forward(t)...); + //return CP(this->kernel())(t...); + } +#else +# define CGAL_CODE(Z,N,_) template \ + Point_d operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t))const{ \ + return CP(this->kernel())(BOOST_PP_ENUM_PARAMS(N,t)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +# undef CGAL_CODE + Point_d operator()()const{ \ + return CP(this->kernel())(); \ + } +#endif + }; + typedef typename Get_functor >::type Construct_vector_d; + typedef typename Get_functor >::type Construct_segment_d; + typedef typename Get_functor >::type Construct_sphere_d; + typedef typename Get_functor >::type Construct_hyperplane_d; + typedef Construct_vector_d Construct_direction_d; + typedef typename Get_functor >::type Construct_line_d; + typedef typename Get_functor >::type Construct_ray_d; + typedef typename Get_functor >::type Construct_iso_box_d; + typedef typename Get_functor >::type Construct_aff_transformation_d; + typedef typename Get_functor >::type Construct_weighted_point_d; + typedef typename Get_functor::type Midpoint_d; + struct Component_accessor_d : private Store_kernel { + typedef Kernel R_; // for the macro + CGAL_FUNCTOR_INIT_STORE(Component_accessor_d) + int dimension(Point_d const&p){ + return this->kernel().point_dimension_d_object()(p); + } + FT cartesian(Point_d const&p, int i){ + return this->kernel().compute_coordinate_d_object()(p,i); + } + RT homogeneous(Point_d const&p, int i){ + if (i == dimension(p)) + return 1; + return cartesian(p, i); + } + }; + struct Construct_cartesian_const_iterator_d : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_cartesian_const_iterator_d) + typedef typename Get_functor >::type CPI; + typedef typename Get_functor >::type CVI; + // FIXME: The following sometimes breaks compilation. The typedef below forces instantiation of this, which forces Point_d, which itself (in the wrapper) needs the derived kernel to tell it what the base kernel is, and that's a cycle. The exact circumstances are not clear, g++ and clang++ are ok in both C++03 and C++11, it is only clang in C++11 without CGAL_CXX11 that breaks. For now, rely on result_type. + //typedef typename CGAL::decay::type>::type result_type; + typedef typename CGAL::decay::type result_type; + // Kernel_d requires a common iterator type for points and vectors + // TODO: provide this mixed functor in preKernel? + //CGAL_static_assertion((boost::is_same::type>::type, result_type>::value)); + CGAL_static_assertion((boost::is_same::type, result_type>::value)); + template + result_type operator()(Point_d const&p, Tag_ t)const{ + return CPI(this->kernel())(p,t); + } + template + result_type operator()(typename First_if_different::Type const&v, Tag_ t)const{ + return CVI(this->kernel())(v,t); + } + + template + result_type operator()(Obj const&o)const{ + return operator()(o, Begin_tag()); + } + result_type operator()(Point_d const&p, int)const{ + return operator()(p, End_tag()); + } + result_type operator()(typename First_if_different::Type const&v, int)const{ + return operator()(v, End_tag()); + } + }; + struct Compute_squared_radius_d : private Store_kernel { + typedef Kernel R_; // for the macro + CGAL_FUNCTOR_INIT_STORE(Compute_squared_radius_d) + typedef FT result_type; + template FT operator()(CGAL_FORWARDABLE(S) s)const{ + return typename Get_functor::type(this->kernel())(CGAL_FORWARD(S,s)); + } + template FT operator()(I b, I e)const{ + return typename Get_functor::type(this->kernel())(b,e); + } + }; + typedef typename Construct_cartesian_const_iterator_d::result_type Cartesian_const_iterator_d; + typedef typename Get_functor::type Squared_distance_d; + typedef typename Get_functor::type Squared_length_d; + typedef typename Get_functor::type Scalar_product_d; + typedef typename Get_functor::type Affine_rank_d; + typedef typename Get_functor::type Affinely_independent_d; + typedef typename Get_functor::type Contained_in_linear_hull_d; + typedef typename Get_functor::type Contained_in_simplex_d; + typedef typename Get_functor::type Has_on_positive_side_d; + typedef typename Get_functor::type Linear_rank_d; + typedef typename Get_functor::type Linearly_independent_d; + typedef typename Get_functor::type Oriented_side_d; + typedef typename Get_functor::type Side_of_bounded_sphere_d; + + typedef typename Get_functor::type Center_of_sphere_d; + typedef Center_of_sphere_d Construct_center_d; // RangeSearchTraits + typedef typename Get_functor::type Construct_circumcenter_d; + typedef typename Get_functor::type Value_at_d; + typedef typename Get_functor::type Point_of_sphere_d; + typedef typename Get_functor::type Orthogonal_vector_d; + typedef typename Get_functor::type Linear_base_d; + typedef typename Get_functor::type Construct_min_vertex_d; + typedef typename Get_functor::type Construct_max_vertex_d; + + typedef typename Get_functor::type Compute_weight_d; + typedef typename Get_functor::type Point_drop_weight_d; + + //TODO: + //typedef ??? Intersect_d; + + + Compute_coordinate_d compute_coordinate_d_object()const{ return Compute_coordinate_d(*this); } + Has_on_positive_side_d has_on_positive_side_d_object()const{ return Has_on_positive_side_d(*this); } + Compare_lexicographically_d compare_lexicographically_d_object()const{ return Compare_lexicographically_d(*this); } + Equal_d equal_d_object()const{ return Equal_d(*this); } + Less_lexicographically_d less_lexicographically_d_object()const{ return Less_lexicographically_d(*this); } + Less_or_equal_lexicographically_d less_or_equal_lexicographically_d_object()const{ return Less_or_equal_lexicographically_d(*this); } + Less_coordinate_d less_coordinate_d_object()const{ return Less_coordinate_d(*this); } + Orientation_d orientation_d_object()const{ return Orientation_d(*this); } + Oriented_side_d oriented_side_d_object()const{ return Oriented_side_d(*this); } + Point_dimension_d point_dimension_d_object()const{ return Point_dimension_d(*this); } + Point_of_sphere_d point_of_sphere_d_object()const{ return Point_of_sphere_d(*this); } + Side_of_oriented_sphere_d side_of_oriented_sphere_d_object()const{ return Side_of_oriented_sphere_d(*this); } + Power_side_of_power_sphere_d power_side_of_power_sphere_d_object()const{ return Power_side_of_power_sphere_d(*this); } + Power_center_d power_center_d_object()const{ return Power_center_d(*this); } + Power_distance_d power_distance_d_object()const{ return Power_distance_d(*this); } + Side_of_bounded_sphere_d side_of_bounded_sphere_d_object()const{ return Side_of_bounded_sphere_d(*this); } + Contained_in_affine_hull_d contained_in_affine_hull_d_object()const{ return Contained_in_affine_hull_d(*this); } + Contained_in_linear_hull_d contained_in_linear_hull_d_object()const{ return Contained_in_linear_hull_d(*this); } + Contained_in_simplex_d contained_in_simplex_d_object()const{ return Contained_in_simplex_d(*this); } + Construct_flat_orientation_d construct_flat_orientation_d_object()const{ return Construct_flat_orientation_d(*this); } + In_flat_orientation_d in_flat_orientation_d_object()const{ return In_flat_orientation_d(*this); } + In_flat_side_of_oriented_sphere_d in_flat_side_of_oriented_sphere_d_object()const{ return In_flat_side_of_oriented_sphere_d(*this); } + In_flat_power_side_of_power_sphere_d in_flat_power_side_of_power_sphere_d_object()const{ return In_flat_power_side_of_power_sphere_d(*this); } + Point_to_vector_d point_to_vector_d_object()const{ return Point_to_vector_d(*this); } + Vector_to_point_d vector_to_point_d_object()const{ return Vector_to_point_d(*this); } + Translated_point_d translated_point_d_object()const{ return Translated_point_d(*this); } + Scaled_vector_d scaled_vector_d_object()const{ return Scaled_vector_d(*this); } + Difference_of_vectors_d difference_of_vectors_d_object()const{ return Difference_of_vectors_d(*this); } + Difference_of_points_d difference_of_points_d_object()const{ return Difference_of_points_d(*this); } + Affine_rank_d affine_rank_d_object()const{ return Affine_rank_d(*this); } + Affinely_independent_d affinely_independent_d_object()const{ return Affinely_independent_d(*this); } + Linear_base_d linear_base_d_object()const{ return Linear_base_d(*this); } + Linear_rank_d linear_rank_d_object()const{ return Linear_rank_d(*this); } + Linearly_independent_d linearly_independent_d_object()const{ return Linearly_independent_d(*this); } + Midpoint_d midpoint_d_object()const{ return Midpoint_d(*this); } + Value_at_d value_at_d_object()const{ return Value_at_d(*this); } + /// Intersect_d intersect_d_object()const{ return Intersect_d(*this); } + Component_accessor_d component_accessor_d_object()const{ return Component_accessor_d(*this); } + Orthogonal_vector_d orthogonal_vector_d_object()const{ return Orthogonal_vector_d(*this); } + Construct_cartesian_const_iterator_d construct_cartesian_const_iterator_d_object()const{ return Construct_cartesian_const_iterator_d(*this); } + Construct_point_d construct_point_d_object()const{ return Construct_point_d(*this); } + Construct_vector_d construct_vector_d_object()const{ return Construct_vector_d(*this); } + Construct_segment_d construct_segment_d_object()const{ return Construct_segment_d(*this); } + Construct_sphere_d construct_sphere_d_object()const{ return Construct_sphere_d(*this); } + Construct_hyperplane_d construct_hyperplane_d_object()const{ return Construct_hyperplane_d(*this); } + Compute_squared_radius_d compute_squared_radius_d_object()const{ return Compute_squared_radius_d(*this); } + Squared_distance_d squared_distance_d_object()const{ return Squared_distance_d(*this); } + Squared_length_d squared_length_d_object()const{ return Squared_length_d(*this); } + Scalar_product_d scalar_product_d_object()const{ return Scalar_product_d(*this); } + Center_of_sphere_d center_of_sphere_d_object()const{ return Center_of_sphere_d(*this); } + Construct_circumcenter_d construct_circumcenter_d_object()const{ return Construct_circumcenter_d(*this); } + Construct_direction_d construct_direction_d_object()const{ return Construct_direction_d(*this); } + Construct_line_d construct_line_d_object()const{ return Construct_line_d(*this); } + Construct_ray_d construct_ray_d_object()const{ return Construct_ray_d(*this); } + Construct_iso_box_d construct_iso_box_d_object()const{ return Construct_iso_box_d(*this); } + Construct_aff_transformation_d construct_aff_transformation_d_object()const{ return Construct_aff_transformation_d(*this); } + Construct_min_vertex_d construct_min_vertex_d_object()const{ return Construct_min_vertex_d(*this); } + Construct_max_vertex_d construct_max_vertex_d_object()const{ return Construct_max_vertex_d(*this); } + Construct_weighted_point_d construct_weighted_point_d_object()const{ return Construct_weighted_point_d(*this); } + + Compute_weight_d compute_weight_d_object()const{ return Compute_weight_d(*this); } + Point_drop_weight_d point_drop_weight_d_object()const{ return Point_drop_weight_d(*this); } + + // Dummies for those required functors missing a concept. + typedef Null_functor Position_on_line_d; + Position_on_line_d position_on_line_d_object()const{return Null_functor();} + typedef Null_functor Barycentric_coordinates_d; + Barycentric_coordinates_d barycentric_coordinates_d_object()const{return Null_functor();} + + /* Not provided because they don't make sense here: + Lift_to_paraboloid_d + Project_along_d_axis_d + */ +}; +} + +#endif // CGAL_KD_KERNEL_D_INTERFACE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h new file mode 100644 index 00000000..99918ed2 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h @@ -0,0 +1,134 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_KO_CONVERTER_H +#define CGAL_KD_KO_CONVERTER_H +#include +#include +#include // First_if_different +#include +namespace CGAL { +template struct KO_converter; +//TODO: It would probably be better if this was a Misc Functor in K1. +// This way K1 could chose how it wants to present its points (sparse +// iterator?) and derived classes would inherit it. + +namespace internal { +template +struct Point_converter_help { + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + typename Get_functor >::type i(k1); + typename Get_functor >::type cp(k2); + return cp(conv(i(p,Begin_tag())),conv(i(p,End_tag()))); + } +}; +#ifdef CGAL_CXX11 +// This doesn't seem so useful, the compiler should be able to handle +// the iterators just as efficiently. +template +struct Point_converter_help,K1,K2> { + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type help(Indices, K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + typename Get_functor::type cc(k1); + typename Get_functor >::type cp(k2); + return cp(conv(cc(p,I))...); + } + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + return help(typename N_increasing_indices::type(),k1,k2,conv,p); + } +}; +#endif +} +template struct KO_converter +: internal::Point_converter_help +{}; + +template struct KO_converter{ + typedef typename Get_type::type K1_Vector; + + // Disabling is now done in KernelD_converter + // // can't use vector without at least a placeholder point because of this + // typedef typename K1:: Point K1_Point; + // typedef typename First_if_different::Type argument_type; + + typedef K1_Vector argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& v) const { + typename Get_functor >::type i(k1); + typename Get_functor >::type cp(k2); + return cp(conv(i(v,Begin_tag())),conv(i(v,End_tag()))); + } +}; + +template struct KO_converter{ + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor::type f(k1); + typename Get_functor >::type cs(k2); + return cs(conv(f(s,0)),conv(f(s,1))); + } +}; + +template struct KO_converter{ + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& h) const { + typename Get_functor::type ov(k1); + typename Get_functor::type ht(k1); + typename Get_functor >::type ch(k2); + return ch(conv(ov(h)),conv(ht(h))); + } +}; + +template struct KO_converter{ + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor::type cos(k1); + typename Get_functor::type sr(k1); + typename Get_functor >::type cs(k2); + return cs(conv(cos(s)),conv(sr(s))); + } +}; + +template struct KO_converter{ + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + template + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor::type pdw(k1); + typename Get_functor::type pw(k1); + typename Get_functor >::type cwp(k2); + return cwp(conv(pdw(s)),conv(pw(s))); + } +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h b/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h new file mode 100644 index 00000000..ddbdc37b --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h @@ -0,0 +1,175 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_LA_EIGEN_H +#define CGAL_LA_EIGEN_H +#include +#ifndef CGAL_EIGEN3_ENABLED +#error Requires Eigen +#endif +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +//FIXME: where could we use Matrix_base instead of Matrix? +// Dim_ real dimension +// Max_dim_ upper bound on the dimension +template struct LA_eigen { + typedef NT_ NT; + typedef Dim_ Dimension; + typedef Max_dim_ Max_dimension; + enum { dimension = Eigen_dimension::value }; + enum { max_dimension = Eigen_dimension::value }; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef LA_eigen< NT, D2, D3 > Other; + }; + template struct Property : boost::false_type {}; + template struct Property : boost::true_type {}; + template struct Property : boost::true_type {}; + template struct Property : boost::true_type {}; + + typedef Eigen::Matrix::value,1,Eigen::ColMajor|Eigen::AutoAlign,Eigen_dimension::value,1> Vector; + typedef Eigen::Matrix Dynamic_vector; + typedef Construct_eigen Construct_vector; + +#if (EIGEN_WORLD_VERSION>=3) + typedef NT const* Vector_const_iterator; +#else + typedef Iterator_from_indices Vector_const_iterator; +#endif + + templatestatic Vector_const_iterator vector_begin(Vec_ const&a){ +#if (EIGEN_WORLD_VERSION>=3) + return &a[0]; +#else + return Vector_const_iterator(a,0); +#endif + } + + templatestatic Vector_const_iterator vector_end(Vec_ const&a){ +#if (EIGEN_WORLD_VERSION>=3) + // FIXME: Isn't that dangerous if a is an expression and not a concrete vector? + return &a[0]+a.size(); +#else + return Vector_const_iterator(a,a.size()); +#endif + } + + typedef Eigen::Matrix Square_matrix; + typedef Eigen::Matrix Dynamic_matrix; + //TODO: don't pass on the values of Max_* for an expensive NT + // typedef ... Constructor + // typedef ... Accessor +#if 0 + private: + template class Canonicalize_vector { + typedef typename Dimension_eigen::type S1; + typedef typename Dimension_eigen::type S2; + public: + typedef typename Vector::type type; + }; + public: +#endif + + templatestatic int size_of_vector(Vec_ const&v){ + return (int)v.size(); + } + + templatestatic NT dot_product(Vec_ const&a,Vec_ const&b){ + return a.dot(b); + } + + template static int rows(Vec_ const&v) { + return (int)v.rows(); + } + template static int columns(Vec_ const&v) { + return (int)v.cols(); + } + + template static NT determinant(Mat_ const&m,bool=false){ + return m.determinant(); + } + + template static typename + Same_uncertainty_nt::type + sign_of_determinant(Mat_ const&m,bool=false) + { + return CGAL::sign(m.determinant()); + } + + template static int rank(Mat_ const&m){ + // return m.rank(); + // This one uses sqrt so cannot be used with Gmpq + // TODO: use different algo for different NT? + // Eigen::ColPivHouseholderQR decomp(m); + Eigen::FullPivLU decomp(m); + // decomp.setThreshold(0); + return static_cast(decomp.rank()); + } + + // m*a==b + template + static void solve(DV&a, DM const&m, V const& b){ + //a = m.colPivHouseholderQr().solve(b); + a = m.fullPivLu().solve(b); + } + template + static bool solve_and_check(DV&a, DM const&m, V const& b){ + //a = m.colPivHouseholderQr().solve(b); + a = m.fullPivLu().solve(b); + return b.isApprox(m*a); + } + + static Dynamic_matrix basis(Dynamic_matrix const&m){ + return m.fullPivLu().image(m); + } + + template static Vector homogeneous_add(Vec1 const&a,Vec2 const&b){ + //TODO: use compile-time size when available + int d=a.size(); + Vector v(d); + v << b[d-1]*a.topRows(d-1)+a[d-1]*b.topRows(d-1), a[d-1]*b[d-1]; + return v; + } + + template static Vector homogeneous_sub(Vec1 const&a,Vec2 const&b){ + int d=a.size(); + Vector v(d); + v << b[d-1]*a.topRows(d-1)-a[d-1]*b.topRows(d-1), a[d-1]*b[d-1]; + return v; + } + + template static std::pair homogeneous_dot_product(Vec1 const&a,Vec2 const&b){ + int d=a.size(); + return make_pair(a.topRows(d-1).dot(b.topRows(d-1)), a[d-1]*b[d-1]); + } + +}; +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h b/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h new file mode 100644 index 00000000..3636996f --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h @@ -0,0 +1,162 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_LA_EIGEN_CONSTRUCTORS_H +#define CGAL_LA_EIGEN_CONSTRUCTORS_H +#include + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4003) // not enough actual parameters for macro 'BOOST_PP_EXPAND_I' + // http://lists.boost.org/boost-users/2014/11/83291.php +#endif + +#ifndef CGAL_EIGEN3_ENABLED +#error Requires Eigen +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + template struct Construct_eigen { + typedef Vector_ result_type; + typedef typename Vector_::Scalar NT; + + private: + static void check_dim(int CGAL_assertion_code(d)){ + CGAL_assertion_code(int m = result_type::MaxSizeAtCompileTime;) + CGAL_assertion((m == Eigen::Dynamic) || (d <= m)); + } + public: + + struct Dimension { + // Initialize with NaN if possible? + result_type operator()(int d) const { + check_dim(d); + return result_type(d); + } + }; + + struct Iterator { + template + result_type operator()(int d,Iter const& f,Iter const& e) const { + check_dim(d); + CGAL_assertion(d==std::distance(f,e)); + result_type a(d); + // TODO: check the right way to do this + std::copy(f,e,&a[0]); + return a; + } + }; + +#if 0 + struct Iterator_add_one { + template + result_type operator()(int d,Iter const& f,Iter const& e) const { + check_dim(d); + CGAL_assertion(d==std::distance(f,e)+1); + result_type a(d); + std::copy(f,e,&a[0]); + a[d-1]=1; + return a; + } + }; +#endif + + struct Iterator_and_last { + template + result_type operator()(int d,Iter const& f,Iter const& e,CGAL_FORWARDABLE(T) t) const { + check_dim(d); + CGAL_assertion(d==std::distance(f,e)+1); + result_type a(d); + std::copy(f,e,&a[0]); + a[d-1]=CGAL_FORWARD(T,t); + return a; + } + }; + +#ifdef CGAL_CXX11 + struct Initializer_list { + // Fix T==NT? + template + result_type operator()(std::initializer_list l) const { + return Iterator()(l.size(),l.begin(),l.end()); + } + }; +#endif + + struct Values { +#ifdef CGAL_CXX11 + // TODO avoid going through Initializer_list which may cause extra copies. Possibly use forward_as_tuple. + template + result_type operator()(U&&...u) const { + check_dim(sizeof...(U)); // TODO: use static_assert + return Initializer_list()({forward_safe(u)...}); + } +#else + +#define CGAL_CODE(Z,N,_) result_type operator()(BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + check_dim(N); \ + result_type a(N); \ + a << BOOST_PP_ENUM_PARAMS(N,t); \ + return a; \ +} +BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE + +#endif + }; + + struct Values_divide { +#ifdef CGAL_CXX11 + template + result_type operator()(H const&h,U&&...u) const { + check_dim(sizeof...(U)); // TODO: use static_assert + return Initializer_list()({Rational_traits().make_rational(std::forward(u),h)...}); + } +#else + +#define CGAL_VAR(Z,N,_) ( Rational_traits().make_rational( t##N ,h) ) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(H const&h, BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + check_dim(N); \ + result_type a(N); \ + a << BOOST_PP_ENUM(N,CGAL_VAR,); \ + return a; \ + } + BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR + +#endif + }; + }; +} +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h b/include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h new file mode 100644 index 00000000..9ecc2b63 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h @@ -0,0 +1,188 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_LAZY_CARTESIAN_H +#define CGAL_KERNEL_D_LAZY_CARTESIAN_H + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +template +struct Nth_iterator_element : private Store_kernel { + Nth_iterator_element(){} + Nth_iterator_element(K const&k):Store_kernel(k){} + typedef typename Get_type::value_tag>::type result_type; + template result_type operator()(CGAL_FORWARDABLE(U) u, int i) const { + typename Get_functor >::type ci(this->kernel()); + return *cpp0x::next(ci(CGAL_FORWARD(U,u),Begin_tag()),i); + } +}; + //typedef typename Functor::nth_element>::type nth_elem; +template::has_nth_element> +struct Select_nth_element_functor { + typedef Nth_iterator_element type; +}; +template +struct Select_nth_element_functor : + Get_functor::nth_element> {}; + +namespace internal { + template + struct Lazy_construction_maybe_nt { + typedef Lazy_construction type; + }; + template + struct Lazy_construction_maybe_nt { + typedef Lazy_construction_nt type; + }; +} + +template +struct Lazy_cartesian_types +{ + typedef typename typeset_intersection< + typename AK_::Object_list, + typename EK_::Object_list + >::type Object_list; + + typedef typename typeset_intersection< + typename AK_::Iterator_list, + typename EK_::Iterator_list + >::type Iterator_list; + + template ::type> struct Type {}; + template struct Type { + typedef Lazy< + typename Get_type::type, + typename Get_type::type, + typename Get_type::type, + E2A_> type; + }; + template struct Type { + typedef CGAL::Lazy_exact_nt::type> type; + }; + + template struct Iterator { + typedef typename iterator_tag_traits::value_tag Vt; + typedef typename Type::type V; + typedef typename Select_nth_element_functor::type AF; + typedef typename Select_nth_element_functor::type EF; + + typedef typename internal::Lazy_construction_maybe_nt< + Kernel_, AF, EF, is_NT_tag::value + >::type nth_elem; + + typedef Iterator_from_indices< + const typename Type::container>::type, + const V, V, nth_elem + > type; + }; +}; + +template +struct Lazy_cartesian : Dimension_base, + Lazy_cartesian_types > +{ + //CGAL_CONSTEXPR Lazy_cartesian(){} + //CGAL_CONSTEXPR Lazy_cartesian(int d):Base_(d){} + + //TODO: Do we want to store an AK and an EK? Or just references? + //FIXME: references would be better I guess. + //TODO: In any case, make sure that we don't end up storing this kernel for + //nothing (it is not empty but references empty kernels or something) + AK_ ak; EK_ ek; + AK_ const& approximate_kernel()const{return ak;} + EK_ const& exact_kernel()const{return ek;} + + typedef Lazy_cartesian Self; + typedef Lazy_cartesian_types Base; + //typedef typename Default::Get::type Kernel; + typedef Self Kernel; + typedef AK_ Approximate_kernel; + typedef EK_ Exact_kernel; + typedef E2A_ E2A; + typedef Approx_converter C2A; + typedef Exact_converter C2E; + + typedef typename Exact_kernel::Rep_tag Rep_tag; + typedef typename Exact_kernel::Kernel_tag Kernel_tag; + typedef typename Exact_kernel::Default_ambient_dimension Default_ambient_dimension; + typedef typename Exact_kernel::Max_ambient_dimension Max_ambient_dimension; + //typedef typename Exact_kernel::Flat_orientation Flat_orientation; + // Check that Approximate_kernel agrees with all that... + + template::type> struct Functor { + typedef Null_functor type; + }; + //FIXME: what do we do with D here? + template struct Functor { + typedef typename Get_functor::type FA; + typedef typename Get_functor::type FE; + typedef Filtered_predicate2 type; + }; + template struct Functor { + typedef typename Get_functor::type FA; + typedef typename Get_functor::type FE; + typedef Lazy_construction_nt type; + }; + template struct Functor { + typedef typename Get_functor::type FA; + typedef typename Get_functor::type FE; + typedef Lazy_construction type; + }; + + //typedef typename Iterator::type Point_cartesian_const_iterator; + //typedef typename Iterator::type Vector_cartesian_const_iterator; + + template + struct Construct_iter : private Store_kernel { + Construct_iter(){} + Construct_iter(Kernel const&k):Store_kernel(k){} + //FIXME: pass the kernel to the functor in the iterator + typedef U result_type; + template + result_type operator()(T const& t,Begin_tag)const{ + return result_type(t,0,this->kernel()); + } + template + result_type operator()(T const& t,End_tag)const{ + return result_type(t,Self().dimension(),this->kernel()); + } + }; + template struct Functor { + typedef Construct_iter::type>::type> type; + }; + + + //TODO: what about other functors of the Misc category? + // for Point_dimension, we should apply it to the approximate point + // for printing, we should??? just not do printing this way? +}; + + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_LAZY_CARTESIAN_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h new file mode 100644 index 00000000..6d9f070f --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h @@ -0,0 +1,59 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_TYPE_AFF_TRANSFORMATION_H +#define CGAL_KD_TYPE_AFF_TRANSFORMATION_H +#include +#include +#include + +// Dummy, that's all the Kernel_d concept requires, so a useful class will wait. + +namespace CGAL { +template +struct Aff_transformation { + typedef R_ R; +}; +namespace CartesianDKernelFunctors { +template struct Construct_aff_transformation { + CGAL_FUNCTOR_INIT_IGNORE(Construct_aff_transformation) + typedef R_ R; + typedef typename Get_type::type result_type; +#ifdef CGAL_CXX11 + template + result_type operator()(T&&...)const{return result_type();} +#else + result_type operator()()const{ + return result_type(); + } +#define CGAL_CODE(Z,N,_) template \ + result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const& BOOST_PP_INTERCEPT))const{ \ + return result_type(); \ + } + BOOST_PP_REPEAT_FROM_TO(1, 9, CGAL_CODE, _ ) +#undef CGAL_CODE + +#endif +}; +} +CGAL_KD_DEFAULT_TYPE(Aff_transformation_tag,(CGAL::Aff_transformation),(),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_aff_transformation),(Aff_transformation_tag),()); + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h new file mode 100644 index 00000000..14e35b01 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h @@ -0,0 +1,159 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_TYPE_HYPERPLANE_H +#define CGAL_KD_TYPE_HYPERPLANE_H +#include +#include +#include +#include +#include +namespace CGAL { +template class Hyperplane { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Vector_; + Vector_ v_; + FT_ s_; + + public: + Hyperplane(Vector_ const&v, FT_ const&s): v_(v), s_(s) {} + // TODO: Add a piecewise constructor? + + Vector_ const& orthogonal_vector()const{return v_;} + FT_ translation()const{return s_;} +}; +namespace CartesianDKernelFunctors { +template struct Construct_hyperplane : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_hyperplane) + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type Vector; + typedef typename Get_type::type FT; + private: + struct One { + typedef int result_type; + templateint const& operator()(T const&)const{ + static const int one = 1; + return one; + } + }; + public: + + result_type operator()(Vector const&a, FT const&b)const{ + return result_type(a,b); + } + // Not really needed + result_type operator()()const{ + typename Get_functor >::type cv(this->kernel()); + return result_type(cv(),0); + } + + template + result_type through(Iter f, Iter e)const{ + typedef typename R_::LA LA; + typedef typename R_::Default_ambient_dimension D1; + typedef typename R_::Max_ambient_dimension D2; + typedef typename Increment_dimension::type D1i; + typedef typename Increment_dimension::type D2i; + + typedef Eigen::Matrix::value, Eigen_dimension::value, + Eigen::ColMajor|Eigen::AutoAlign, Eigen_dimension::value, Eigen_dimension::value> Matrix; + typedef Eigen::Matrix::value, 1, + Eigen::ColMajor|Eigen::AutoAlign, Eigen_dimension::value, 1> Vec; + typename Get_functor::type c(this->kernel()); + typename Get_functor >::type cv(this->kernel()); + typename Get_functor::type pd(this->kernel()); + + Point const& p0=*f; + int d = pd(p0); + Matrix m(d,d+1); + for(int j=0;j lu(m); + Vec res = lu.kernel().col(0); + return this->operator()(cv(d,LA::vector_begin(res),LA::vector_end(res)-1),res(d)); + } + template + result_type operator()(Iter f, Iter e, Point const&p, CGAL::Oriented_side s=ON_ORIENTED_BOUNDARY)const{ + result_type ret = through(f, e); + // I don't really like using ON_ORIENTED_BOUNDARY to mean that we don't care, we might as well not pass 'p' at all. + if (s == ON_ORIENTED_BOUNDARY) + return ret; + typename Get_functor::type os(this->kernel()); + CGAL::Oriented_side o = os(ret, p); + if (o == ON_ORIENTED_BOUNDARY || o == s) + return ret; + typename Get_functor::type ov(this->kernel()); + typename Get_functor >::type cv(this->kernel()); + return this->operator()(ov(ret.orthogonal_vector()), -ret.translation()); + } +}; +template struct Orthogonal_vector { + CGAL_FUNCTOR_INIT_IGNORE(Orthogonal_vector) + typedef typename Get_type::type Hyperplane; + typedef typename Get_type::type const& result_type; + result_type operator()(Hyperplane const&s)const{ + return s.orthogonal_vector(); + } +}; +template struct Hyperplane_translation { + CGAL_FUNCTOR_INIT_IGNORE(Hyperplane_translation) + typedef typename Get_type::type Hyperplane; + typedef typename Get_type::type result_type; + // TODO: Is_exact? + result_type operator()(Hyperplane const&s)const{ + return s.translation(); + } +}; +template struct Value_at : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Value_at) + typedef typename Get_type::type Hyperplane; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_type::type FT; + typedef FT result_type; + typedef typename Get_functor::type Dot; + typedef typename Get_functor::type P2V; + result_type operator()(Hyperplane const&h, Point const&p)const{ + Dot dot(this->kernel()); + P2V p2v(this->kernel()); + return dot(h.orthogonal_vector(),p2v(p)); + // Use Orthogonal_vector to make it generic? + // Copy the code from Scalar_product to avoid p2v? + } +}; +} +//TODO: Add a condition that the hyperplane type is the one from this file. +CGAL_KD_DEFAULT_TYPE(Hyperplane_tag,(CGAL::Hyperplane),(Vector_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_hyperplane),(Vector_tag,Hyperplane_tag),(Opposite_vector_tag,Oriented_side_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Orthogonal_vector_tag,(CartesianDKernelFunctors::Orthogonal_vector),(Vector_tag,Hyperplane_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Hyperplane_translation_tag,(CartesianDKernelFunctors::Hyperplane_translation),(Hyperplane_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Value_at_tag,(CartesianDKernelFunctors::Value_at),(Point_tag,Vector_tag,Hyperplane_tag),(Scalar_product_tag,Point_to_vector_tag)); +} // namespace CGAL +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h new file mode 100644 index 00000000..d053f351 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h @@ -0,0 +1,88 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNELD_TYPES_ISO_BOX_H +#define CGAL_KERNELD_TYPES_ISO_BOX_H +#include +#include +#include +#include +#include +namespace CGAL { +template class Iso_box { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + typedef std::pair Data_; + Data_ data; + public: + Iso_box(){} + Iso_box(Point_ const&a, Point_ const&b): data(a,b) {} + Point_ min BOOST_PREVENT_MACRO_SUBSTITUTION ()const{ + return data.first; + } + Point_ max BOOST_PREVENT_MACRO_SUBSTITUTION ()const{ + return data.second; + } +}; +namespace CartesianDKernelFunctors { + template struct Construct_iso_box : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_iso_box) + typedef typename Get_type::type result_type; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type Cp_; + typedef typename Get_functor >::type Ci_; + result_type operator()(Point const&a, Point const&b)const{ + Cp_ cp(this->kernel()); + Ci_ ci(this->kernel()); + return result_type(cp( + make_transforming_pair_iterator(ci(a,Begin_tag()), ci(b,Begin_tag()), Min()), + make_transforming_pair_iterator(ci(a,End_tag()), ci(b,End_tag()), Min())), + cp( + make_transforming_pair_iterator(ci(a,Begin_tag()), ci(b,Begin_tag()), Max()), + make_transforming_pair_iterator(ci(a,End_tag()), ci(b,End_tag()), Max()))); + } + }; + + template struct Construct_min_vertex { + CGAL_FUNCTOR_INIT_IGNORE(Construct_min_vertex) + typedef typename Get_type::type argument_type; + //TODO: make result_type a reference + typedef typename Get_type::type result_type; + result_type operator()(argument_type const&b)const{ + return b.min BOOST_PREVENT_MACRO_SUBSTITUTION (); + } + }; + template struct Construct_max_vertex { + CGAL_FUNCTOR_INIT_IGNORE(Construct_max_vertex) + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + result_type operator()(argument_type const&b)const{ + return b.max BOOST_PREVENT_MACRO_SUBSTITUTION (); + } + }; +} +//TODO (other types as well) only enable these functors if the Iso_box type is the one defined in this file... +CGAL_KD_DEFAULT_TYPE(Iso_box_tag,(CGAL::Iso_box),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_iso_box),(Iso_box_tag,Point_tag),(Construct_ttag,Construct_ttag)); +CGAL_KD_DEFAULT_FUNCTOR(Construct_min_vertex_tag,(CartesianDKernelFunctors::Construct_min_vertex),(Iso_box_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_max_vertex_tag,(CartesianDKernelFunctors::Construct_max_vertex),(Iso_box_tag),()); +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_ISO_BOX_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h new file mode 100644 index 00000000..6a09571c --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNELD_TYPES_LINE_H +#define CGAL_KERNELD_TYPES_LINE_H +#include +#include +#include +namespace CGAL { +template class Line { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + typedef std::pair Data_; + Data_ data; + public: + Line(){} + Line(Point_ const&a, Point_ const&b): data(a,b) {} + Point_ point(int i)const{ + if(i==0) return data.first; + if(i==1) return data.second; + throw "not implemented"; + } + Line opposite()const{ + return Line(data.second,data.first); + } +}; +namespace CartesianDKernelFunctors { + template struct Construct_line : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_line) + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type Vector; + typedef typename Get_functor::type Tp_; + //typedef typename Get_functor::type Dp_; + //typedef typename Get_functor::type Sv_; + result_type operator()(Point const&a, Point const&b)const{ + return result_type(a,b); + } + result_type operator()(Point const&a, typename First_if_different::Type const&b)const{ + Tp_ tp(this->kernel()); + return result_type(a,tp(a,b)); + } + }; +} +CGAL_KD_DEFAULT_TYPE(Line_tag,(CGAL::Line),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_line),(Line_tag,Point_tag,Vector_tag),(Translated_point_tag)); + +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_LINE_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h new file mode 100644 index 00000000..be845e76 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNELD_TYPES_RAY_H +#define CGAL_KERNELD_TYPES_RAY_H +#include +#include +#include +namespace CGAL { +template class Ray { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + typedef typename Get_type::type Vector_; + typedef std::pair Data_; + Data_ data; + public: + Ray(){} + Ray(Point_ const&a, Vector_ const&b): data(a,b) {} + Point_ source()const{ + return data.first; + } + // FIXME: return a R_::Direction? + Vector_ direction()const{ + return data.second; + } +}; +namespace CartesianDKernelFunctors { + template struct Construct_ray : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_ray) + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type Vector; + typedef typename Get_functor::type Dp_; + //typedef typename Get_functor::type Tp_; + //typedef typename Get_functor::type Sv_; + result_type operator()(Point const&a, Vector const&b)const{ + return result_type(a,b); + } + result_type operator()(Point const&a, typename First_if_different::Type const&b)const{ + Dp_ dp(this->kernel()); + return result_type(a,dp(b,a)); + } + }; +} +CGAL_KD_DEFAULT_TYPE(Ray_tag,(CGAL::Ray),(Point_tag,Vector_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_ray),(Point_tag,Ray_tag,Vector_tag),(Difference_of_points_tag)); + +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_RAY_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h new file mode 100644 index 00000000..38361c2b --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h @@ -0,0 +1,121 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNELD_SEGMENTD_H +#define CGAL_KERNELD_SEGMENTD_H +#include +#include +#include +namespace CGAL { +template class Segment { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + //typedef typename R_::Vector Vector_; + //typedef typename Get_functor >::type Cv_; +// typedef typename R_::Squared_distance Csd_; + typedef std::pair Data_; + Data_ data; + public: + //typedef Segmentd Segment; +#ifdef CGAL_CXX11 + //FIXME: don't forward directly, piecewise_constuct should call the point construction functor (I guess? or is it unnecessary?) + template::type...>,std::tuple>::value>::type> + Segment(U&&...u):data(std::forward(u)...){} +#else + Segment(){} + Segment(Point_ const&a, Point_ const&b): data(a,b) {} + //template + //Segment(A const&,T1 const&t1,T2 const&t2) +#endif + Point_ source()const{return data.first;} + Point_ target()const{return data.second;} + Point_ operator[](int i)const{ + if((i%2)==0) + return source(); + else + return target(); + } + Segment opposite()const{ + return Segment(target(),source()); + } + //Vector_ vector()const{ + // return Cv_()(data.first,data.second); + //} +// FT_ squared_length()const{ +// return Csd_()(data.first,data.second); +// } +}; + +namespace CartesianDKernelFunctors { + +template struct Construct_segment : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_segment) + typedef R_ R; + typedef typename Get_type::type Point; + typedef typename Get_type::type Segment; + typedef typename Get_functor >::type CP; + typedef Segment result_type; + result_type operator()(Point const&a, Point const&b)const{ + return result_type(a,b); + } + // Not really needed, especially since it forces us to store the kernel + result_type operator()()const{ + Point p = typename Get_functor >::type (this->kernel()) (); + return result_type (p, p); + } + // T should only be std::piecewise_construct_t, but we shouldn't fail if it doesn't exist. + template + result_type operator()(CGAL_FORWARDABLE(T),CGAL_FORWARDABLE(U) u,CGAL_FORWARDABLE(V) v)const{ + CP cp(this->kernel()); + result_type r = {{ + call_on_tuple_elements(cp, CGAL_FORWARD(U,u)), + call_on_tuple_elements(cp, CGAL_FORWARD(V,v)) }}; + return r; + } +}; + +// This should be part of Construct_point, according to Kernel_23 conventions +template struct Segment_extremity { + CGAL_FUNCTOR_INIT_IGNORE(Segment_extremity) + typedef R_ R; + typedef typename Get_type::type Point; + typedef typename Get_type::type Segment; + typedef Point result_type; + result_type operator()(Segment const&s, int i)const{ + if(i==0) return s.source(); + CGAL_assertion(i==1); + return s.target(); + } +#ifdef CGAL_CXX11 + result_type operator()(Segment &&s, int i)const{ + if(i==0) return std::move(s.source()); + CGAL_assertion(i==1); + return std::move(s.target()); + } +#endif +}; +} // CartesianDKernelFunctors + +CGAL_KD_DEFAULT_TYPE(Segment_tag,(CGAL::Segment),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_segment),(Segment_tag,Point_tag),(Construct_ttag)); +CGAL_KD_DEFAULT_FUNCTOR(Segment_extremity_tag,(CartesianDKernelFunctors::Segment_extremity),(Segment_tag,Point_tag),()); + +} // namespace CGAL + +#endif // CGAL_KERNELD_SEGMENTD_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h new file mode 100644 index 00000000..114410b4 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h @@ -0,0 +1,132 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_TYPE_SPHERE_H +#define CGAL_KD_TYPE_SPHERE_H +#include +#include +namespace CGAL { +template class Sphere { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + Point_ c_; + FT_ r2_; + + public: + Sphere(Point_ const&p, FT_ const&r2): c_(p), r2_(r2) {} + // TODO: Add a piecewise constructor? + + Point_ const& center()const{return c_;} + FT_ const& squared_radius()const{return r2_;} +}; + +namespace CartesianDKernelFunctors { +template struct Construct_sphere : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_sphere) + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type FT; + result_type operator()(Point const&a, FT const&b)const{ + return result_type(a,b); + } + // Not really needed + result_type operator()()const{ + typename Get_functor >::type cp(this->kernel()); + return result_type(cp(),0); + } + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type cc(this->kernel()); + typename Get_functor::type sd(this->kernel()); + + // It should be possible to avoid copying the center by moving this code to a constructor. + Point center = cc(f, e); + FT const& r2 = sd(center, *f); + return this->operator()(CGAL_MOVE(center), r2); + } +}; + +template struct Center_of_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Center_of_sphere) + typedef typename Get_type::type Sphere; + // No reference because of the second overload + typedef typename Get_type::type result_type; + + result_type const& operator()(Sphere const&s)const{ + return s.center(); + } + + template + result_type operator()(Iter b, Iter e)const{ + typename Get_functor >::type cs(this->kernel()); + return operator()(cs(b,e)); // computes the radius needlessly + } +}; + +template struct Squared_radius { + CGAL_FUNCTOR_INIT_IGNORE(Squared_radius) + typedef typename Get_type::type Sphere; + typedef typename Get_type::type const& result_type; + // TODO: Is_exact? + result_type operator()(Sphere const&s)const{ + return s.squared_radius(); + } +}; + +// FIXME: Move it to the generic functors, using the two above and conditional to the existence of sqrt(FT) +template struct Point_of_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Point_of_sphere) + typedef R_ R; + typedef typename Get_type::type FT; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_type::type Sphere; + typedef typename Get_functor >::type CP; + typedef typename Get_functor >::type CI; + typedef typename Get_functor::type PD; + typedef Point result_type; + typedef Sphere first_argument_type; + typedef int second_argument_type; + struct Trans : std::binary_function { + FT const& r_; int idx; bool sgn; + Trans (int n, FT const& r, bool b) : r_(r), idx(n), sgn(b) {} + FT operator()(FT const&x, int i)const{ + return (i == idx) ? sgn ? x + r_ : x - r_ : x; + } + }; + result_type operator()(Sphere const&s, int i)const{ + CI ci(this->kernel()); + PD pd(this->kernel()); + typedef boost::counting_iterator Count; + Point const&c = s.center(); + int d=pd(c); + bool last = (i == d); + FT r = sqrt(s.squared_radius()); + Trans t(last ? 0 : i, r, !last); + return CP(this->kernel())(make_transforming_pair_iterator(ci(c,Begin_tag()),Count(0),t),make_transforming_pair_iterator(ci(c,End_tag()),Count(d),t)); + } +}; +} +CGAL_KD_DEFAULT_TYPE(Sphere_tag,(CGAL::Sphere),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_sphere),(Sphere_tag,Point_tag),(Construct_ttag,Compute_point_cartesian_coordinate_tag,Squared_distance_tag,Squared_distance_to_origin_tag,Point_dimension_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Center_of_sphere_tag,(CartesianDKernelFunctors::Center_of_sphere),(Sphere_tag,Point_tag),(Construct_ttag)); +CGAL_KD_DEFAULT_FUNCTOR(Squared_radius_tag,(CartesianDKernelFunctors::Squared_radius),(Sphere_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_of_sphere_tag,(CartesianDKernelFunctors::Point_of_sphere),(Sphere_tag,Point_tag),(Construct_ttag, Construct_ttag)); +} // namespace CGAL +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h b/include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h new file mode 100644 index 00000000..1caf8701 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h @@ -0,0 +1,205 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_TYPE_WP_H +#define CGAL_KD_TYPE_WP_H +#include +#include +namespace CGAL { +namespace KerD { +template class Weighted_point { + typedef typename Get_type::type FT_; + typedef typename Get_type::type Point_; + Point_ c_; + FT_ w_; + + public: + Weighted_point(Point_ const&p, FT_ const&w): c_(p), w_(w) {} + // TODO: Add a piecewise constructor? + + Point_ const& point()const{return c_;} + FT_ const& weight()const{return w_;} +}; +} + +namespace CartesianDKernelFunctors { +template struct Construct_weighted_point : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_weighted_point) + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type FT; + result_type operator()(Point const&a, FT const&b)const{ + return result_type(a,b); + } + // Not really needed + result_type operator()()const{ + typename Get_functor >::type cp(this->kernel()); + return result_type(cp(),0); + } +}; + +template struct Point_drop_weight { + CGAL_FUNCTOR_INIT_IGNORE(Point_drop_weight) + typedef typename Get_type::type argument_type; + typedef typename Get_type::type const& result_type; + // Returning a reference is fragile + + result_type operator()(argument_type const&s)const{ + return s.point(); + } +}; + +template struct Point_weight { + CGAL_FUNCTOR_INIT_IGNORE(Point_weight) + typedef typename Get_type::type argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(argument_type const&s)const{ + return s.weight(); + } +}; + +template struct Power_distance : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Power_distance) + typedef typename Get_type::type first_argument_type; + typedef first_argument_type second_argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(first_argument_type const&a, second_argument_type const&b)const{ + typename Get_functor::type pdw(this->kernel()); + typename Get_functor::type pw(this->kernel()); + typename Get_functor::type sd(this->kernel()); + return sd(pdw(a),pdw(b))-pw(a)-pw(b); + } +}; +template struct Power_distance_to_point : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Power_distance_to_point) + typedef typename Get_type::type first_argument_type; + typedef typename Get_type::type second_argument_type; + typedef typename Get_type::type result_type; + + result_type operator()(first_argument_type const&a, second_argument_type const&b)const{ + typename Get_functor::type pdw(this->kernel()); + typename Get_functor::type pw(this->kernel()); + typename Get_functor::type sd(this->kernel()); + return sd(pdw(a),b)-pw(a); + } +}; + +template struct Power_side_of_power_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Power_side_of_power_sphere) + typedef R_ R; + typedef typename Get_type::type result_type; + + template + result_type operator()(Iter const& f, Iter const& e, Pt const& p0) const { + typename Get_functor::type ptr(this->kernel()); + typename Get_functor::type pdw(this->kernel()); + typename Get_functor::type pw(this->kernel()); + return ptr ( + make_transforming_iterator (f, pdw), + make_transforming_iterator (e, pdw), + make_transforming_iterator (f, pw), + pdw (p0), + pw (p0)); + } +}; + +template struct In_flat_power_side_of_power_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(In_flat_power_side_of_power_sphere) + typedef R_ R; + typedef typename Get_type::type result_type; + + template + result_type operator()(Fo const& fo, Iter const& f, Iter const& e, Pt const& p0) const { + typename Get_functor::type ptr(this->kernel()); + typename Get_functor::type pdw(this->kernel()); + typename Get_functor::type pw(this->kernel()); + return ptr ( + fo, + make_transforming_iterator (f, pdw), + make_transforming_iterator (e, pdw), + make_transforming_iterator (f, pw), + pdw (p0), + pw (p0)); + } +}; + +// Construct a point at (weighted) distance 0 from all the input +template struct Power_center : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Power_center) + typedef typename Get_type::type WPoint; + typedef WPoint result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type FT; + template + result_type operator()(Iter f, Iter e)const{ + // 2*(x-y).c == (x^2-wx^2)-(y^2-wy^2) + typedef typename R_::LA LA; + typedef typename LA::Square_matrix Matrix; + typedef typename LA::Vector Vec; + typedef typename LA::Construct_vector CVec; + typename Get_functor::type c(this->kernel()); + typename Get_functor >::type cp(this->kernel()); + typename Get_functor::type pd(this->kernel()); + typename Get_functor::type sdo(this->kernel()); + typename Get_functor::type pdp(this->kernel()); + typename Get_functor::type pdw(this->kernel()); + typename Get_functor::type pw(this->kernel()); + typename Get_functor >::type cwp(this->kernel()); + + WPoint const& wp0 = *f; + Point const& p0 = pdw(wp0); + int d = pd(p0); + FT const& n0 = sdo(p0) - pw(wp0); + Matrix m(d,d); + Vec b = typename CVec::Dimension()(d); + // Write the point coordinates in lines. + int i; + for(i=0; ++f!=e; ++i) { + WPoint const& wp=*f; + Point const& p=pdw(wp); + FT const& np = sdo(p) - pw(wp); + for(int j=0;j),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag,(CartesianDKernelFunctors::Construct_weighted_point),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_drop_weight_tag,(CartesianDKernelFunctors::Point_drop_weight),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_weight_tag,(CartesianDKernelFunctors::Point_weight),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Power_side_of_power_sphere_tag,(CartesianDKernelFunctors::Power_side_of_power_sphere),(Weighted_point_tag),(Power_side_of_power_sphere_raw_tag,Point_drop_weight_tag,Point_weight_tag)); +CGAL_KD_DEFAULT_FUNCTOR(In_flat_power_side_of_power_sphere_tag,(CartesianDKernelFunctors::In_flat_power_side_of_power_sphere),(Weighted_point_tag),(In_flat_power_side_of_power_sphere_raw_tag,Point_drop_weight_tag,Point_weight_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Power_distance_tag,(CartesianDKernelFunctors::Power_distance),(Weighted_point_tag,Point_tag),(Squared_distance_tag,Point_drop_weight_tag,Point_weight_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Power_distance_to_point_tag,(CartesianDKernelFunctors::Power_distance_to_point),(Weighted_point_tag,Point_tag),(Squared_distance_tag,Point_drop_weight_tag,Point_weight_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Power_center_tag,(CartesianDKernelFunctors::Power_center),(Weighted_point_tag,Point_tag),(Compute_point_cartesian_coordinate_tag,Construct_ttag,Construct_ttag,Point_dimension_tag,Squared_distance_to_origin_tag,Point_drop_weight_tag,Point_weight_tag,Power_distance_to_point_tag)); +} // namespace CGAL +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h new file mode 100644 index 00000000..0ad9bb36 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h @@ -0,0 +1,165 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_ARRAY_H +#define CGAL_VECTOR_ARRAY_H +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +namespace CGAL { + +// May not be safe to use with dim!=max_dim. +// In that case, we should store the real dim next to the array. +template struct Array_vector { + typedef NT_ NT; + typedef Dim_ Dimension; + typedef Max_dim_ Max_dimension; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef Array_vector< NT, D2, D3 > Other; + }; + template struct Property : boost::false_type {}; + + static const unsigned d_=Max_dim_::value; + CGAL_static_assertion(d_ != (unsigned)UNKNOWN_DIMENSION); + + typedef cpp0x::array Vector; + struct Construct_vector { + struct Dimension { + // Initialize with NaN if possible? + Vector operator()(unsigned CGAL_assertion_code(d)) const { + CGAL_assertion(d<=d_); + return Vector(); + } + }; + + struct Iterator { + template + Vector operator()(unsigned CGAL_assertion_code(d),Iter const& f,Iter const& e) const { + CGAL_assertion(d==(unsigned) std::distance(f,e)); + CGAL_assertion(d<=d_); + //TODO: optimize for forward iterators + Vector a; + std::copy(f,e,a.begin()); + return a; + } + }; + +#if 0 + struct Iterator_add_one { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e) const { + CGAL_assertion(d==std::distance(f,e)+1); + CGAL_assertion(d<=d_); + //TODO: optimize + Vector a; + std::copy(f,e,a.begin()); + a.back()=1; + return a; + } + }; +#endif + + struct Iterator_and_last { + template + Vector operator()(unsigned CGAL_assertion_code(d),Iter const& f,Iter const& e,CGAL_FORWARDABLE(T) t) const { + CGAL_assertion(d==std::distance(f,e)+1); + CGAL_assertion(d<=d_); + //TODO: optimize for forward iterators + Vector a; + std::copy(f,e,a.begin()); + a.back()=CGAL_FORWARD(T,t); + return a; + } + }; + + struct Values { +#ifdef CGAL_CXX11 + template + Vector operator()(U&&...u) const { + static_assert(sizeof...(U)<=d_,"too many arguments"); + Vector a={{forward_safe(u)...}}; + return a; + } +#else + +#define CGAL_CODE(Z,N,_) Vector operator()(BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + CGAL_assertion(N<=d_); \ + Vector a={{BOOST_PP_ENUM_PARAMS(N,t)}}; \ + return a; \ +} +BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE + +#endif + }; + + struct Values_divide { +#ifdef CGAL_CXX11 + template + Vector operator()(H const& h,U&&...u) const { + static_assert(sizeof...(U)<=d_,"too many arguments"); + Vector a={{Rational_traits().make_rational(std::forward(u),h)...}}; + return a; + } +#else + +#define CGAL_VAR(Z,N,_) Rational_traits().make_rational( t##N , h) +#define CGAL_CODE(Z,N,_) template Vector \ + operator()(H const&h, BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + CGAL_assertion(N<=d_); \ + Vector a={{BOOST_PP_ENUM(N,CGAL_VAR,_)}}; \ + return a; \ + } + BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR + +#endif + }; + }; + + typedef NT const* Vector_const_iterator; + static Vector_const_iterator vector_begin(Vector const&a){ + return &a[0]; + } + static Vector_const_iterator vector_end(Vector const&a){ + return &a[0]+d_; // Don't know the real size + } + static unsigned size_of_vector(Vector const&){ + return d_; // Don't know the real size + } + +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h new file mode 100644 index 00000000..954a3c1b --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h @@ -0,0 +1,213 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_AVX4_H +#define CGAL_VECTOR_AVX4_H + +#if !defined __AVX__ || (__GNUC__ * 100 + __GNUC_MINOR__ < 408) +#error Requires AVX and gcc 4.8+ +#endif +#include + +#include +#include +#include // CGAL::Sign +#include // CGAL::sign + + + +namespace CGAL { + + struct Avx_vector_4 { + typedef double NT; + typedef Dimension_tag<4> Dimension; + typedef Dimension_tag<4> Max_dimension; + // No Rebind_dimension, this is a building block + template struct Property : boost::false_type {}; + template struct Property + : boost::true_type {}; + /* MAYBE? + template struct Property + : boost::true_type {}; + */ + template struct Property + : boost::true_type {}; + template struct Property + : boost::true_type {}; + template struct Property + : boost::true_type {}; + + typedef __m256d Vector; + struct Construct_vector { + struct Dimension { + // Initialize with NaN? + Vector operator()(unsigned d) const { + CGAL_assertion(d==4); + return Vector(); + } + }; + + struct Iterator { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e) const { + CGAL_assertion(d==4); + double x0 = *f; + double x1 = *++f; + double x2 = *++f; + double x3 = *++f; + CGAL_assertion(++f==e); + Vector a = { x0, x1, x2, x3 }; + return a; + } + }; + + struct Iterator_and_last { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e,double t) const { + CGAL_assertion(d==4); + double x0 = *f; + double x1 = *++f; + double x2 = *++f; + CGAL_assertion(++f==e); + Vector a = { x0, x1, x2, t }; + return a; + } + }; + + struct Values { + Vector operator()(double a,double b,double c,double d) const { + Vector r = { a, b, c, d }; + return r; + } + }; + + struct Values_divide { + Vector operator()(double h,double a,double b,double c,double d) const { + // {a,b,c,d}/{h,h,h,h} should be roughly the same + Vector r = { a/h, b/h, c/h, d/h }; + return r; + } + }; + }; + + public: + typedef double const* Vector_const_iterator; + static inline Vector_const_iterator vector_begin(Vector const&a){ + return (Vector_const_iterator)(&a); + } + static inline Vector_const_iterator vector_end(Vector const&a){ + return (Vector_const_iterator)(&a)+4; + } + static inline unsigned size_of_vector(Vector){ + return 4; + } + static inline double dot_product(__m256d x, __m256d y){ + __m256d p=x*y; + __m256d z=_mm256_hadd_pd(p,p); + return z[0]+z[2]; + } + private: + static inline __m256d avx_sym(__m256d x){ +#if 0 + return __builtin_shuffle(x,(__m256i){2,3,0,1}); +#else + return _mm256_permute2f128_pd(x,x,1); +#endif + } + static inline __m256d avx_left(__m256d x){ +#if 0 + return __builtin_shuffle(x,(__m256i){1,2,3,0}); +#else +#ifdef __AVX2__ + return _mm256_permute4x64_pd(x,1+2*4+3*16+0*64); +#else + __m256d s = _mm256_permute2f128_pd(x,x,1); + return _mm256_shuffle_pd(x,s,5); +#endif +#endif + } + static inline __m256d avx_right(__m256d x){ +#if 0 + return __builtin_shuffle(x,(__m256i){3,0,1,2}); +#else +#ifdef __AVX2__ + return _mm256_permute4x64_pd(x,3+0*4+1*16+2*64); +#else + __m256d s = _mm256_permute2f128_pd(x,x,1); + return _mm256_shuffle_pd(s,x,5); +#endif +#endif + } + static inline double avx_altprod(__m256d x, __m256d y){ + __m256d p=x*y; + __m256d z=_mm256_hsub_pd(p,p); + return z[0]+z[2]; + } + public: + static double + determinant_of_vectors(Vector a, Vector b, Vector c, Vector d) { + __m256d x=a*avx_left(b)-avx_left(a)*b; + __m256d yy=a*avx_sym(b); + __m256d y=yy-avx_sym(yy); + __m256d z0=x*avx_sym(c); + __m256d z1=avx_left(x)*c; + __m256d z2=y*avx_left(c); + __m256d z=z0+z1-z2; + return avx_altprod(z,avx_right(d)); + } + static CGAL::Sign + sign_of_determinant_of_vectors(Vector a, Vector b, Vector c, Vector d) { + return CGAL::sign(determinant_of_vectors(a,b,c,d)); + } + + private: + static inline __m256d avx3_right(__m256d x){ +#if 0 + return __builtin_shuffle(x,(__m256i){2,0,1,3}); // can replace 3 with anything +#else +#ifdef __AVX2__ + return _mm256_permute4x64_pd(x,2+0*4+1*16+3*64); +#else + __m256d s = _mm256_permute2f128_pd(x,x,1); + return _mm256_shuffle_pd(s,x,12); +#endif +#endif + } + public: + static inline double dot_product_omit_last(__m256d x, __m256d y){ + __m256d p=x*y; + __m128d q=_mm256_extractf128_pd(p,0); + double z=_mm_hadd_pd(q,q)[0]; + return z+p[2]; + } + // Note: without AVX2, is it faster than the scalar computation? + static double + determinant_of_vectors_omit_last(Vector a, Vector b, Vector c) { + __m256d x=a*avx3_right(b)-avx3_right(a)*b; + return dot_product_omit_last(c,avx3_right(x)); + } + static CGAL::Sign + sign_of_determinant_of_vectors_omit_last(Vector a, Vector b, Vector c) { + return CGAL::sign(determinant_of_vectors_omit_last(a,b,c)); + } + + }; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h new file mode 100644 index 00000000..b8efbe28 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h @@ -0,0 +1,76 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_DET_ITER_PTS_ITER_VEC_H +#define CGAL_VECTOR_DET_ITER_PTS_ITER_VEC_H +#include +#include +#include +#include + +namespace CGAL { + +template ::value, + bool = LA::template Property::value> +struct Add_determinant_of_iterator_to_points_from_iterator_to_vectors : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_iterator_to_vectors Other; + }; +}; + +template +struct Add_determinant_of_iterator_to_points_from_iterator_to_vectors + : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_iterator_to_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + // TODO: use std::minus, boost::bind, etc + template struct Minus_fixed { + T const& a; + Minus_fixed(T const&a_):a(a_){} + T operator()(T const&b)const{return b-a;} + }; + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Minus_fixed f(a); + return LA::determinant_of_iterator_to_vectors(make_transforming_iterator(first,f),make_transforming_iterator(end,f)); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Minus_fixed f(a); + return LA::sign_of_determinant_of_iterator_to_vectors(make_transforming_iterator(first,f),make_transforming_iterator(end,f)); + } +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h new file mode 100644 index 00000000..71a31d81 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h @@ -0,0 +1,211 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_DET_ITER_PTS_PTS_H +#define CGAL_VECTOR_DET_ITER_PTS_PTS_H +#include +#include + +namespace CGAL { + +template ::value, + bool = LA::template Property::value> +struct Add_determinant_of_iterator_to_points_from_points : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template +struct Add_determinant_of_iterator_to_points_from_points +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; CGAL_assertion(++first==end); + return LA::determinant_of_points(a,b,c); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_points(a,b,c); + } +}; + +template +struct Add_determinant_of_iterator_to_points_from_points +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; CGAL_assertion(++first==end); + return LA::determinant_of_points(a,b,c,d); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_points(a,b,c,d); + } +}; + +template +struct Add_determinant_of_iterator_to_points_from_points +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; CGAL_assertion(++first==end); + return LA::determinant_of_points(a,b,c,d,e); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_points(a,b,c,d,e); + } +}; + +template +struct Add_determinant_of_iterator_to_points_from_points +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; CGAL_assertion(++first==end); + return LA::determinant_of_points(a,b,c,d,e,f); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_points(a,b,c,d,e,f); + } +}; + +template +struct Add_determinant_of_iterator_to_points_from_points +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_points_from_points Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; ++first; + Vector const&g=*first; CGAL_assertion(++first==end); + return LA::determinant_of_points(a,b,c,d,e,f,g); + } + template + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; ++first; + Vector const&g=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_points(a,b,c,d,e,f,g); + } +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h new file mode 100644 index 00000000..f096d6c7 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h @@ -0,0 +1,201 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_DET_ITER_VEC_VEC_H +#define CGAL_VECTOR_DET_ITER_VEC_VEC_H +#include +#include + +namespace CGAL { + +template ::value, + bool = LA::template Property::value> +struct Add_determinant_of_iterator_to_vectors_from_vectors : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template +struct Add_determinant_of_iterator_to_vectors_from_vectors +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; CGAL_assertion(++first==end); + return LA::determinant_of_vectors(a,b); + } + template + static Sign sign_of_determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_vectors(a,b); + } +}; + +template +struct Add_determinant_of_iterator_to_vectors_from_vectors +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; CGAL_assertion(++first==end); + return LA::determinant_of_vectors(a,b,c); + } + template + static Sign sign_of_determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_vectors(a,b,c); + } +}; + +template +struct Add_determinant_of_iterator_to_vectors_from_vectors +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; CGAL_assertion(++first==end); + return LA::determinant_of_vectors(a,b,c,d); + } + template + static Sign sign_of_determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_vectors(a,b,c,d); + } +}; + +template +struct Add_determinant_of_iterator_to_vectors_from_vectors +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; CGAL_assertion(++first==end); + return LA::determinant_of_vectors(a,b,c,d,e); + } + template + static Sign sign_of_determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_vectors(a,b,c,d,e); + } +}; + +template +struct Add_determinant_of_iterator_to_vectors_from_vectors +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + template + static NT determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; CGAL_assertion(++first==end); + return LA::determinant_of_vectors(a,b,c,d,e,f); + } + template + static Sign sign_of_determinant_of_iterator_to_vectors(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Vector const&b=*first; ++first; + Vector const&c=*first; ++first; + Vector const&d=*first; ++first; + Vector const&e=*first; ++first; + Vector const&f=*first; CGAL_assertion(++first==end); + return LA::sign_of_determinant_of_vectors(a,b,c,d,e,f); + } +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h new file mode 100644 index 00000000..7ddb73c3 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h @@ -0,0 +1,164 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_DETPTS_H +#define CGAL_VECTOR_DETPTS_H +#include +#include + +namespace CGAL { + +template ::value, + bool = LA::template Property::value + && LA::template Property::value> +struct Add_determinant_of_points_from_vectors_and_minus : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template +struct Add_determinant_of_points_from_vectors_and_minus +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT determinant_of_points(Vector const&a, Vector const&b, + Vector const&c){ + return LA::determinant_of_vectors(b-a,c-a); + } + static Sign sign_of_determinant_of_points(Vector const&a, Vector const&b, + Vector const&c){ + return LA::sign_of_determinant_of_vectors(b-a,c-a); + } +}; + +template +struct Add_determinant_of_points_from_vectors_and_minus +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return LA::determinant_of_vectors(b-a,c-a,d-a); + } + static Sign sign_of_determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return LA::sign_of_determinant_of_vectors(b-a,c-a,d-a); + } +}; + +template +struct Add_determinant_of_points_from_vectors_and_minus +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return LA::determinant_of_vectors(b-a,c-a,d-a,e-a); + } + static Sign sign_of_determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return LA::sign_of_determinant_of_vectors(b-a,c-a,d-a,e-a); + } +}; + +template +struct Add_determinant_of_points_from_vectors_and_minus +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return LA::determinant_of_vectors(b-a,c-a,d-a,e-a,f-a); + } + static Sign sign_of_determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return LA::sign_of_determinant_of_vectors(b-a,c-a,d-a,e-a,f-a); + } +}; + +template +struct Add_determinant_of_points_from_vectors_and_minus +, Max_dim_, false, true> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef Add_determinant_of_points_from_vectors_and_minus Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f, + Vector const&g){ + return LA::determinant_of_vectors(b-a,c-a,d-a,e-a,f-a,g-a); + } + static Sign sign_of_determinant_of_points(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f, + Vector const&g){ + return LA::sign_of_determinant_of_vectors(b-a,c-a,d-a,e-a,f-a,g-a); + } +}; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h new file mode 100644 index 00000000..64eafe69 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_DETVEC_SMALL_H +#define CGAL_VECTOR_DETVEC_SMALL_H +#include +#include +#include + +#define CGAL_ALLOWED_INCLUSION 1 + +#define CGAL_CLASS Add_determinant_of_vectors_small_dim +#define CGAL_TAG Has_determinant_of_vectors_tag +#define CGAL_FUNC determinant_of_vectors +#define CGAL_SIGN_FUNC sign_of_determinant_of_vectors +#define CGAL_SHIFT 0 + +#include + +#undef CGAL_CLASS +#undef CGAL_TAG +#undef CGAL_FUNC +#undef CGAL_SIGN_FUNC +#undef CGAL_SHIFT + +#define CGAL_CLASS Add_determinant_of_vectors_omit_last_small_dim +#define CGAL_TAG Has_determinant_of_vectors_omit_last_tag +#define CGAL_FUNC determinant_of_vectors_omit_last +#define CGAL_SIGN_FUNC sign_of_determinant_of_vectors_omit_last +#define CGAL_SHIFT 1 + +#include + +#undef CGAL_CLASS +#undef CGAL_TAG +#undef CGAL_FUNC +#undef CGAL_SIGN_FUNC +#undef CGAL_SHIFT + +#undef CGAL_ALLOWED_INCLUSION + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h new file mode 100644 index 00000000..b4856742 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h @@ -0,0 +1,164 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_ALLOWED_INCLUSION +#error Must not include this header directly +#endif +#if !defined(CGAL_TAG) \ + || ! defined(CGAL_CLASS) \ + || ! defined(CGAL_FUNC) \ + || ! defined(CGAL_SIGN_FUNC) \ + || ! defined(CGAL_SHIFT) + +#error Forgot one macro +#endif + +namespace CGAL { + +template ::value> +struct CGAL_CLASS : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; +}; + +template +struct CGAL_CLASS +, Max_dim_, false> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b){ + return CGAL::determinant_of_vectors(a,b); + } + template + static Sign CGAL_SIGN_FUNC(V1 const&a, V2 const&b){ + return CGAL::sign_of_determinant_of_vectors(a,b); + } +}; + +template +struct CGAL_CLASS +, Max_dim_, false> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c){ + return CGAL::determinant_of_vectors(a,b,c); + } + static Sign CGAL_SIGN_FUNC(Vector const&a, Vector const&b, + Vector const&c){ + return CGAL::sign_of_determinant_of_vectors(a,b,c); + } +}; + +template +struct CGAL_CLASS +, Max_dim_, false> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return CGAL::determinant_of_vectors(a,b,c,d); + } + static Sign CGAL_SIGN_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return CGAL::sign_of_determinant_of_vectors(a,b,c,d); + } +}; + +template +struct CGAL_CLASS +, Max_dim_, false> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return CGAL::determinant_of_vectors(a,b,c,d,e); + } + static Sign CGAL_SIGN_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return CGAL::sign_of_determinant_of_vectors(a,b,c,d,e); + } +}; + +template +struct CGAL_CLASS +, Max_dim_, false> : LA { + typedef typename LA::NT NT; + typedef typename LA::Vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension LA2; + typedef CGAL_CLASS Other; + }; + template struct Property : LA::template Property

{}; + template struct Property : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return CGAL::determinant_of_vectors(a,b,c,d,e,f); + } + static Sign CGAL_SIGN_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return CGAL::sign_of_determinant_of_vectors(a,b,c,d,e,f); + } +}; + +} diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h new file mode 100644 index 00000000..d4cfeeb1 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h @@ -0,0 +1,46 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KD_MIX_VECTOR_H +#define CGAL_KD_MIX_VECTOR_H +#include +namespace CGAL { + +template +struct Mix_vector +: Dynamic_::template Rebind_dimension::Other +{ + template + struct Rebind_dimension { + typedef Mix_vector Other; + }; +}; + +template +struct Mix_vector, Max_dim_> +: Static_::template Rebind_dimension, Max_dim_>::Other +{ + template + struct Rebind_dimension { + typedef Mix_vector Other; + }; +}; +} +#endif + diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h new file mode 100644 index 00000000..2a75385c --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h @@ -0,0 +1,145 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_SSE2_H +#define CGAL_VECTOR_SSE2_H + +// Check what needs adapting for clang, intel and microsoft +#if !defined __SSE2__ || (__GNUC__ * 100 + __GNUC_MINOR__ < 408) +#error Requires SSE2 and gcc 4.8+ +#endif +#include // FIXME: other platforms call it differently + +#include +#include +#include // CGAL::Sign +#include // CGAL::sign + + + +namespace CGAL { + + struct Sse_vector_2 { + typedef double NT; + typedef Dimension_tag<2> Dimension; + typedef Dimension_tag<2> Max_dimension; + // No Rebind_dimension, this is a building block + template struct Property : boost::false_type {}; + template struct Property + : boost::true_type {}; + /* MAYBE? + template struct Property + : boost::true_type {}; + */ + template struct Property + : boost::true_type {}; + template struct Property + : boost::true_type {}; + + typedef __m128d Vector; + struct Construct_vector { + struct Dimension { + // Initialize with NaN? + Vector operator()(unsigned d) const { + CGAL_assertion(d==2); + return Vector(); + } + }; + + struct Iterator { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e) const { + CGAL_assertion(d==2); + double x0 = *f; + double x1 = *++f; + CGAL_assertion(++f==e); + Vector a = { x0, x1 }; + return a; + } + }; + + struct Iterator_and_last { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e,double t) const { + CGAL_assertion(d==2); + Vector a = { *f, t }; + CGAL_assertion(++f==e); + return a; + } + }; + + struct Values { + Vector operator()(double a,double b) const { + Vector r = { a, b }; + return r; + } + }; + + struct Values_divide { + Vector operator()(double h,double a,double b) const { + // {a,b}/{h,h} is probably slower + Vector r = { a/h, b/h }; + return r; + } + }; + }; + + typedef double const* Vector_const_iterator; + static inline Vector_const_iterator vector_begin(Vector const&a){ + return (Vector_const_iterator)(&a); + } + static inline Vector_const_iterator vector_end(Vector const&a){ + return (Vector_const_iterator)(&a)+2; + } + static inline unsigned size_of_vector(Vector){ + return 2; + } + public: + + static double determinant_of_vectors(Vector a, Vector b) { + __m128d c = _mm_shuffle_pd (b, b, 1); // b1, b0 + __m128d d = a * c; // a0*b1, a1*b0 +#ifdef __SSE3__ + __m128d e = _mm_hsub_pd (d, d); + return e[0]; +#else + return d[0]-d[1]; +#endif + } + static CGAL::Sign sign_of_determinant_of_vectors(Vector a, Vector b) { + return CGAL::sign(determinant_of_vectors(a,b)); + } + + static double dot_product(Vector a,Vector b){ +#ifdef __SSE4_1__ + return _mm_dp_pd (a, b, 1+16+32)[0]; +#else + __m128d p = a * b; +#if defined __SSE3__ + __m128d s = _mm_hadd_pd (p, p); + return s[0]; +#else + return p[0]+p[1]; +#endif +#endif + }; + }; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h new file mode 100644 index 00000000..b85a3734 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h @@ -0,0 +1,181 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_2INT_H +#define CGAL_VECTOR_2INT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// What are the pros and cons of having NT be int vs double? + +namespace CGAL { + struct Vector_2_int_prop1 { + typedef double NT; // try lying a bit + typedef int32_t NT1; // what is really stored + typedef int32_t NT1b; // slightly longer + typedef int_fast64_t NT2; // longer type for computations + typedef int_fast64_t NT2b; // slightly longer + bool check_limits(int32_t x){return std::abs(x)<(1<<30);} + // TODO: find nice bounds + }; +#ifdef __SIZEOF_INT128__ + struct Vector_2_int_prop2 { + typedef double NT; + typedef int32_t NT1; + typedef int_fast64_t NT1b; + typedef int_fast64_t NT2; + typedef __int128 NT2b; + bool check_limits(int32_t){return true;} + // take a template/int64_t input and still check the limits? + }; + struct Vector_2_int_prop3 { + typedef long double NT; + typedef int64_t NT1; + typedef int64_t NT1b; + typedef __int128 NT2; + typedef __int128 NT2b; + enum { has_limit=true }; + bool check_limits(int32_t x){return std::abs(x)<(1L<<62);} + // TODO: find nice bounds + }; +#endif + + template + struct Vector_2_int : Prop { + using typename Prop::NT; + using typename Prop::NT1; + using typename Prop::NT1b; + using typename Prop::NT2; + using typename Prop::NT2b; + using Prop::check_limits; + + typedef Dimension_tag<2> Dimension; + typedef Dimension_tag<2> Max_dimension; + // No Rebind_dimension, this is a building block + template struct Property : boost::false_type {}; + //template struct Property + // : boost::true_type {}; + template struct Property + : boost::true_type {}; + //template struct Property + // : boost::true_type {}; + // Advertise somehow that the sign_of_determinant* are exact? + + typedef cpp0x::array Vector; + struct Construct_vector { + struct Dimension { + Vector operator()(unsigned d) const { + CGAL_assertion(d==2); + return Vector(); + } + }; + + // TODO (for all constructors): check that input fits in NT1... + struct Iterator { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e) const { + CGAL_assertion(d==2); + NT1 x0 = *f; + NT1 x1 = *++f; + CGAL_assertion (++f == e); + CGAL_assertion (check_limits(x0) && check_limits(x1)); + Vector a = { x0, x1 }; + return a; + } + }; + + struct Iterator_and_last { + template + Vector operator()(unsigned d,Iter const& f,Iter const& e,double t) const { + CGAL_assertion(d==2); + NT1 x = *f; + CGAL_assertion (++f == e); + CGAL_assertion (check_limits(x) && check_limits(t)); + Vector a = { x, t }; + return a; + } + }; + + struct Values { + Vector operator()(NT1 a,NT1 b) const { + CGAL_assertion (check_limits(a) && check_limits(b)); + Vector r = { a, b }; + return r; + } + }; + + /* + // Maybe safer not to provide it + struct Values_divide { + Vector operator()(double h,double a,double b) const { + Vector r = { a/h, b/h }; + return r; + } + }; + */ + }; + + // Since we lie about NT, be consistent about it + typedef transforming_iterator,NT1 const*> Vector_const_iterator; + static inline Vector_const_iterator vector_begin(Vector const&a){ + return Vector_const_iterator(a.begin()); + } + static inline Vector_const_iterator vector_end(Vector const&a){ + return Vector_const_iterator(a.end()); + } + static inline unsigned size_of_vector(Vector){ + return 2; + } + + // for unsigned NT1, check what changes to do. + // return NT or NT2? + static NT determinant_of_vectors(Vector a, Vector b) { + return CGAL::determinant_of_vectors(a,b); + } + static CGAL::Sign sign_of_determinant_of_vectors(Vector a, Vector b) { + return CGAL::sign_of_determinant_of_vectors(a,b); + } + + static NT determinant_of_points(Vector a, Vector b, Vector c) { + // could be faster to convert to NT directly + NT1b a0=a[0]; NT1b a1=a[1]; + NT1b x0=b[0]-a0; NT1b x1=b[1]-a1; + NT1b y0=c[0]-a0; NT1b y1=c[1]-a1; + return CGAL::determinant(x0,x1,y0,y1); + } + static CGAL::Sign sign_of_determinant_of_points(Vector a, Vector b, Vector c) { + NT1b a0=a[0]; NT1b a1=a[1]; + NT1b x0=b[0]-a0; NT1b x1=b[1]-a1; + NT2b y0=c[0]-a0; NT2b y1=c[1]-a1; + return CGAL::compare(x0*y1,x1*y0); + } + }; + +} +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h b/include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h new file mode 100644 index 00000000..f9cc4e3c --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h @@ -0,0 +1,167 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_VECTOR_VECTOR_H +#define CGAL_VECTOR_VECTOR_H +#include +#include +#include +#include +#include +#include +#include +namespace CGAL { + +//Derive from a class that doesn't depend on Dim, or still use Dim for checking? +template struct Vector_vector { + typedef NT_ NT; + typedef Dim_ Dimension; + typedef Max_dim_ Max_dimension; + typedef std::vector Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef Vector_vector< NT, D2, D3 > Other; + }; + template struct Property : boost::false_type {}; + + struct Construct_vector { + struct Dimension { + Vector operator()(int d) const { + return Vector(d); + } + }; + + struct Iterator { + template + Vector operator()(int CGAL_assertion_code(d),Iter const& f,Iter const& e) const { + CGAL_assertion(d==std::distance(f,e)); + return Vector(f,e); + } + }; + + // unneeded thanks to Iterator_and_last? +#if 0 + struct Iterator_add_one { + template + Vector operator()(int CGAL_assertion_code(d),Iter const& f,Iter const& e) const { + CGAL_assertion(d==std::distance(f,e)+1); + Vector a; + a.reserve(d+1); + a.insert(a.end(),f,e); + a.push_back(1); + return a; + } + }; +#endif + + struct Iterator_and_last { + template + Vector operator()(int d,Iter const& f,Iter const& e,CGAL_FORWARDABLE(T) t) const { + CGAL_assertion(d==std::distance(f,e)+1); + Vector a; + a.reserve(d+1); + a.insert(a.end(),f,e); + a.push_back(CGAL_FORWARD(T,t)); + return a; + } + }; + + // useless, use a transform_iterator? +#if 0 + struct Iterator_and_last_divide { + template + Vector operator()(int d,Iter f,Iter const& e,T const&t) const { + CGAL_assertion(d==std::distance(f,e)+1); + Vector a; + a.reserve(d+1); + for(;f!=e;++f){ + a.push_back(*f/t); + } + return a; + } + }; +#endif + + struct Values { +#ifdef CGAL_CXX11 + template + Vector operator()(U&&...u) const { + //TODO: check the right number of {}, g++ accepts one and two + Vector a={forward_safe(u)...}; + return a; + } +#else + +#define CGAL_VAR(Z,N,_) a.push_back(t##N); +#define CGAL_CODE(Z,N,_) Vector operator()(BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + Vector a; \ + a.reserve(N); \ + BOOST_PP_REPEAT(N,CGAL_VAR,) \ + return a; \ +} +BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR + +#endif + }; + + struct Values_divide { +#ifdef CGAL_CXX11 + template + Vector operator()(H const&h,U&&...u) const { + //TODO: do we want to cast at some point? + //e.g. to avoid 1/2 in integers + // ==> use Rational_traits().make_rational(x,y) ? + Vector a={Rational_traits().make_rational(std::forward(u),h)...}; + return a; + } +#else + +#define CGAL_VAR(Z,N,_) a.push_back(Rational_traits().make_rational( t##N ,h)); +#define CGAL_CODE(Z,N,_) template Vector \ + operator()(H const&h, BOOST_PP_ENUM_PARAMS(N,NT const& t)) const { \ + Vector a; \ + a.reserve(N); \ + BOOST_PP_REPEAT(N,CGAL_VAR,) \ + return a; \ + } + BOOST_PP_REPEAT_FROM_TO(1, 11, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR + +#endif + }; + }; + typedef typename Vector::const_iterator Vector_const_iterator; + static Vector_const_iterator vector_begin(Vector const&a){ + return a.begin(); + } + static Vector_const_iterator vector_end(Vector const&a){ + return a.end(); + } + static int size_of_vector(Vector const&a){ + return (int)a.size(); + } +}; + + +} +#endif + diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h new file mode 100644 index 00000000..44e9aa96 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h @@ -0,0 +1,305 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_CARTESIAN_WRAP_H +#define CGAL_KERNEL_D_CARTESIAN_WRAP_H + +#include +#include + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4003) // not enough actual parameters for macro 'BOOST_PP_EXPAND_I' + // http://lists.boost.org/boost-users/2014/11/83291.php +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +//TODO: do we want to store the kernel ref in the Object wrappers? It would allow for additions and operator[] and things like that to work, but objects would still need to be created by functors. + +namespace CGAL { +namespace internal { +BOOST_MPL_HAS_XXX_TRAIT_DEF(Is_wrapper) +template::value> struct Is_wrapper { + enum { value=false }; + typedef Tag_false type; +}; +template struct Is_wrapper { + typedef typename T::Is_wrapper type; + enum { value=type::value }; +}; + +template::value> struct Is_wrapper_iterator { + enum { value=false }; + typedef Tag_false type; +}; +template struct Is_wrapper_iterator : + Is_wrapper::type>::value_type> +{ }; + +struct Forward_rep { +//TODO: make a good C++0X version with perfect forwarding +//#ifdef CGAL_CXX11 +//template ::type>::value&&!Is_wrapper_iterator::type>::value>::type> +//T&& operator()(typename std::remove_reference::type&& t) const {return static_cast(t);}; +//template ::type>::value&&!Is_wrapper_iterator::type>::value>::type> +//T&& operator()(typename std::remove_reference::type& t) const {return static_cast(t);}; +// +//template ::type>::value>::type> +//typename Type_copy_cvref::type::Rep>::type&& +//operator()(T&& t) const { +// return static_cast::type::Rep>::type&&>(t.rep()); +//}; +// +//template ::type>::value>::type> +//transforming_iterator::type> +//operator()(T&& t) const { +// return make_transforming_iterator(std::forward(t),Forward_rep()); +//}; +//#else +template ::value,bool=Is_wrapper_iterator::value> struct result_; +template struct result_{typedef T const& type;}; +template struct result_{typedef typename decay::type::Rep const& type;}; +template struct result_{typedef transforming_iterator::type> type;}; +template struct result; +template struct result : result_ {}; + +template typename boost::disable_if,Is_wrapper_iterator >,T>::type const& operator()(T const& t) const {return t;} +template typename boost::disable_if,Is_wrapper_iterator >,T>::type& operator()(T& t) const {return t;} + +template typename T::Rep const& operator()(T const& t, typename boost::enable_if >::type* = 0) const {return t.rep();} + +template transforming_iterator,T>::type> operator()(T const& t) const {return make_transforming_iterator(t,Forward_rep());} +//#endif +}; +} + +template ::value> +struct Map_wrapping_type : Get_type {}; +#define CGAL_REGISTER_OBJECT_WRAPPER(X) \ + template \ + struct Map_wrapping_type { \ + typedef Wrap::X##_d type; \ + } +CGAL_REGISTER_OBJECT_WRAPPER(Point); +CGAL_REGISTER_OBJECT_WRAPPER(Vector); +CGAL_REGISTER_OBJECT_WRAPPER(Segment); +CGAL_REGISTER_OBJECT_WRAPPER(Sphere); +CGAL_REGISTER_OBJECT_WRAPPER(Hyperplane); +CGAL_REGISTER_OBJECT_WRAPPER(Weighted_point); +#undef CGAL_REGISTER_OBJECT_WRAPPER + +// Note: this tends to be an all or nothing thing currently, wrapping +// only some types breaks, probably because we don't check whether the +// return type is indeed wrapped. +template < typename Base_ , typename Derived_ = Default > +struct Cartesian_wrap : public Base_ +{ + CGAL_CONSTEXPR Cartesian_wrap(){} + CGAL_CONSTEXPR Cartesian_wrap(int d):Base_(d){} + typedef Base_ Kernel_base; + typedef Cartesian_wrap Self; + // TODO: pass the 2 types Self and Derived to the wrappers, they can use Self for most purposes and Derived only for Kernel_traits' typedef R. + typedef typename Default::Get::type Derived; + // FIXME: The list doesn't belong here. + typedef boost::mpl::vector Wrapped_list; + + template + struct Type : Map_wrapping_type {}; + + //Translate the arguments + template ::type, + bool=Provides_functor::value, + bool=boost::mpl::contains::type>::type::value> + struct Functor { + typedef typename Get_functor::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename B::result_type result_type; +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + return b(internal::Forward_rep()(u)...); + } +#else +#define CGAL_VAR(Z,N,_) internal::Forward_rep()(u##N) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u))const{ \ + return b(BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE +#undef CGAL_VAR +// In case the last argument needs to be non-const. Fragile... +#define CGAL_VAR(Z,N,_) internal::Forward_rep()(u##N) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u),V&v)const{ \ + return b(BOOST_PP_ENUM(N,CGAL_VAR,),internal::Forward_rep()(v)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,8,CGAL_CODE,_) +#undef CGAL_CODE +#undef CGAL_VAR +#endif + }; + }; + + // Preserve the difference between Null_functor and nothing. + template + struct Functor + : Get_functor {}; + + //Translate both the arguments and the result + //TODO: Check Is_wrapper instead of relying on map_result_tag? + template struct Functor { + typedef typename Get_functor::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename map_result_tag::type result_tag; + // FIXME: Self or Derived? + typedef typename Get_type::type result_type; +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + return result_type(Eval_functor(),b,internal::Forward_rep()(u)...); + } +#else +#define CGAL_VAR(Z,N,_) internal::Forward_rep()(u##N) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u))const{ \ + return result_type(Eval_functor(),b,BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE +#undef CGAL_VAR +#endif + }; + }; + +}; + +template < typename Base_ > +struct Cartesian_refcount : public Base_ +{ + CGAL_CONSTEXPR Cartesian_refcount(){} + CGAL_CONSTEXPR Cartesian_refcount(int d):Base_(d){} + typedef Base_ Kernel_base; + typedef Cartesian_refcount Self; + + // FIXME: Use object_list, or a list passed as argument, or anything + // automatic. + template struct Type : Get_type {}; +#define CGAL_Kernel_obj(X,Y) \ + template struct Type { typedef Ref_count_obj type; }; + + CGAL_Kernel_obj(Point,point) + CGAL_Kernel_obj(Vector,vector) +#undef CGAL_Kernel_obj + + template struct Dispatch { + //typedef typename map_functor_type::type f_t; + typedef typename map_result_tag::type r_t; + enum { + is_nul = boost::is_same::type,Null_functor>::value, + ret_rcobj = boost::is_same::value || boost::is_same::value + }; + }; + + //Translate the arguments + template::is_nul,bool=Dispatch::ret_rcobj> struct Functor { + typedef typename Get_functor::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename B::result_type result_type; +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + return b(internal::Forward_rep()(u)...); + } +#else + result_type operator()()const{ + return b(); + } +#define CGAL_VAR(Z,N,_) internal::Forward_rep()(u##N) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u))const{ \ + return b(BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE +#undef CGAL_VAR +#endif + }; + }; + + //Translate both the arguments and the result + template struct Functor { + typedef Null_functor type; + }; + + template struct Functor { + typedef typename Get_functor::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename map_result_tag::type result_tag; + typedef typename Get_type::type result_type; +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + return result_type(Eval_functor(),b,internal::Forward_rep()(u)...); + } +#else + result_type operator()()const{ + return result_type(Eval_functor(),b); + } +#define CGAL_VAR(Z,N,_) internal::Forward_rep()(u##N) +#define CGAL_CODE(Z,N,_) template result_type \ + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u))const{ \ + return result_type(Eval_functor(),b,BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE +#undef CGAL_VAR +#endif + }; + }; + +}; + +} //namespace CGAL + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif // CGAL_KERNEL_D_CARTESIAN_WRAP_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h new file mode 100644 index 00000000..54fd50bd --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h @@ -0,0 +1,131 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_HYPERPLANE_D_H +#define CGAL_WRAPPER_HYPERPLANE_D_H + +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Hyperplane_d : public Get_type::type +{ + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Vector_; + typedef typename Get_functor >::type CHBase; + typedef typename Get_functor::type OVBase; + typedef typename Get_functor::type HTBase; + + typedef Hyperplane_d Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef typename Increment_dimension::type Feature_dimension; + + typedef typename Get_type::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Hyperplane_d(U&&...u) + : Rep(CHBase()(std::forward(u)...)){} + +// // called from Construct_point_d +// template explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Hyperplane_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Point_d(Point_d const&)=default; + Point_d(Point_d &);//=default; + Point_d(Point_d &&)=default; +#endif + + // try not to use these + Hyperplane_d(Rep const& v) : Rep(v) {} + Hyperplane_d(Rep& v) : Rep(static_cast(v)) {} + Hyperplane_d(Rep&& v) : Rep(std::move(v)) {} + +#else + + Hyperplane_d() : Rep(CHBase()()) {} + + Hyperplane_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Hyperplane_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CHBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Hyperplane_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Point_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + +#endif + + //TODO: if OVBase returns a reference to a base vector, cast it to a + //reference to a wrapper vector. Ugly but should be safe. + Vector_ orthogonal_vector()const{ + return Vector_(Eval_functor(),OVBase(),rep()); + } + FT_ translation()const{ + return HTBase()(rep()); + } + + +}; + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_SPHERE_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h new file mode 100644 index 00000000..0718c947 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h @@ -0,0 +1,284 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_POINT_D_H +#define CGAL_WRAPPER_POINT_D_H + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Point_d : public Get_type::type + // Deriving won't work if the point is just a __m256d. + // Test boost/std::is_class for instance +{ + typedef typename Get_type::type RT_; + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Vector_; + typedef typename Get_functor >::type CPBase; + typedef typename Get_functor::type CCBase; + typedef typename Get_functor >::type CPI; + + + typedef Point_d Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef Dimension_tag<0> Feature_dimension; + + typedef typename Get_type::type Rep; + //typedef typename CGAL::decay::type>::type Cartesian_const_iterator; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Point_d(U&&...u) + : Rep(CPBase()(std::forward(u)...)){} + +// // called from Construct_point_d +// template explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Point_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Point_d(Point_d const&)=default; + Point_d(Point_d &);//=default; + Point_d(Point_d &&)=default; +#endif + + // try not to use these + Point_d(Rep const& v) : Rep(v) {} + Point_d(Rep& v) : Rep(static_cast(v)) {} + Point_d(Rep&& v) : Rep(std::move(v)) {} + + // this one should be implicit + Point_d(Origin const& v) + : Rep(CPBase()(v)) {} + Point_d(Origin& v) + : Rep(CPBase()(v)) {} + Point_d(Origin&& v) + : Rep(CPBase()(std::move(v))) {} + +#else + + Point_d() : Rep(CPBase()()) {} + + Point_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Point_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CPBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Point_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Point_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + + // this one should be implicit + Point_d(Origin const& o) + : Rep(CPBase()(o)) {} + +#endif + + typename boost::result_of::type cartesian(int i)const{ + return CCBase()(rep(),i); + } + typename boost::result_of::type operator[](int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of::type cartesian_begin()const{ + return CPI()(rep(),Begin_tag()); + } + + typename boost::result_of::type cartesian_end()const{ + return CPI()(rep(),End_tag()); + } + + int dimension() const { + typedef typename Get_functor::type PDBase; + return PDBase()(rep()); + } + + /* + Direction_d direction() const + { + return R().construct_direction_d_object()(*this); + } + + Vector_d transform(const Aff_transformation_d &t) const + { + return t.transform(*this); + } + + Vector_d operator/(const RT& c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + Vector_d operator/(const typename First_if_different::Type & c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + typename Qualified_result_of::type + x() const + { + return R().compute_x_3_object()(*this); + } + + typename Qualified_result_of::type + y() const + { + return R().compute_y_3_object()(*this); + } + + typename Qualified_result_of::type + z() const + { + return R().compute_z_3_object()(*this); + } + + typename Qualified_result_of::type + hx() const + { + return R().compute_hx_3_object()(*this); + } + + typename Qualified_result_of::type + hy() const + { + return R().compute_hy_3_object()(*this); + } + + typename Qualified_result_of::type + hz() const + { + return R().compute_hz_3_object()(*this); + } + + typename Qualified_result_of::type + hw() const + { + return R().compute_hw_3_object()(*this); + } + + typename Qualified_result_of::type + cartesian(int i) const + { + CGAL_kernel_precondition( (i == 0) || (i == 1) || (i == 2) ); + if (i==0) return x(); + if (i==1) return y(); + return z(); + } + + typename Qualified_result_of::type + homogeneous(int i) const + { + CGAL_kernel_precondition( (i >= 0) || (i <= 3) ); + if (i==0) return hx(); + if (i==1) return hy(); + if (i==2) return hz(); + return hw(); + } + + typename Qualified_result_of::type + squared_length() const + { + return R().compute_squared_length_3_object()(*this); + } +*/ +}; +#if 0 +template Point_d::Point_d(Point_d &)=default; +#endif + +//TODO: IO + +template +std::ostream& operator <<(std::ostream& os, const Point_d& p) +{ + typedef typename R_::Kernel_base Kbase; + typedef typename Get_functor >::type CPI; + // Should just be "auto"... + typename CGAL::decay::Rep,Begin_tag) + >::type>::type + b = p.cartesian_begin(), + e = p.cartesian_end(); + os << p.dimension(); + for(; b != e; ++b){ + os << " " << *b; + } + return os; +} + +//template +//Vector_d operator+(const Vector_d& v,const Vector_d& w) const +//{ +// return typename R::template Construct::type()(v,w); +//} +// +//template +//Vector_d operator-(const Vector_d& v,const Vector_d& w) const +//{ +// return typename R::template Construct::type()(v,w); +//} + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_POINT_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h new file mode 100644 index 00000000..f33e14c0 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h @@ -0,0 +1,120 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_REF_COUNT_OBJ_H +#define CGAL_WRAPPER_REF_COUNT_OBJ_H + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +// no need for a fancy interface here, people can use the Point_d wrapper on +// top. + +namespace CGAL { + +template +class Ref_count_obj +{ + typedef typename R_::Kernel_base Kbase; + typedef typename Get_functor >::type CBase; + + typedef Ref_count_obj Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + typedef R_ R; + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + //typedef Dimension_tag<0> Feature_dimension; + + typedef typename Get_type::type Rep; + typedef Handle_for Data; + +private: + Data data; +public: + + const Rep& rep() const + { + return CGAL::get_pointee_or_identity(data); + } + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Ref_count_obj(U&&...u) + : data(Eval_functor(),CBase(),std::forward(u)...){} + + template explicit Ref_count_obj(Eval_functor&&,F&&f,U&&...u) + : data(Eval_functor(),std::forward(f),std::forward(u)...){} + + // try not to use these + Ref_count_obj(Rep const& v) : data(v) {} + Ref_count_obj(Rep& v) : data(static_cast(v)) {} + Ref_count_obj(Rep&& v) : data(std::move(v)) {} + + // Do we really need this for point? +// // this one should be implicit +// Ref_count_obj(Origin const& v) +// : data(Eval_functor(),CBase(),v) {} +// Ref_count_obj(Origin& v) +// : data(Eval_functor(),CBase(),v) {} +// Ref_count_obj(Origin&& v) +// : data(Eval_functor(),CBase(),std::move(v)) {} + +#else + + Ref_count_obj() : data(Eval_functor(),CBase()) {} + + Ref_count_obj(Rep const& v) : data(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Ref_count_obj(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : data(Eval_functor(),CBase(),BOOST_PP_ENUM_PARAMS(N,t)) {} \ + \ + template \ + Ref_count_obj(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : data(Eval_functor(),f,BOOST_PP_ENUM_PARAMS(N,t)) {} + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + template + Ref_count_obj(Eval_functor,F const& f) + : data(Eval_functor(),f) {} + +// // this one should be implicit +// Ref_count_obj(Origin const& o) +// : data(Eval_functor(),CBase(),o) {} + +#endif + +}; + +} //namespace CGAL + +#endif diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h new file mode 100644 index 00000000..bfb20a77 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h @@ -0,0 +1,133 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_SEGMENT_D_H +#define CGAL_WRAPPER_SEGMENT_D_H + +#include +#include +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Segment_d : public Get_type::type +{ + typedef typename Get_type::type RT_; + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Point_; + typedef typename Get_functor >::type CPBase; + typedef typename Get_functor >::type CSBase; + typedef typename Get_functor::type CSEBase; + + typedef Segment_d Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef Dimension_tag<1> Feature_dimension; + + typedef typename Get_type::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Segment_d(U&&...u) + : Rep(CSBase()(std::forward(u)...)){} + +// // called from Construct_point_d +// template explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Segment_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Point_d(Point_d const&)=default; + Point_d(Point_d &);//=default; + Point_d(Point_d &&)=default; +#endif + + // try not to use these + Segment_d(Rep const& v) : Rep(v) {} + Segment_d(Rep& v) : Rep(static_cast(v)) {} + Segment_d(Rep&& v) : Rep(std::move(v)) {} + +#else + + Segment_d() : Rep(CSBase()()) {} + + Segment_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Segment_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CSBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Segment_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Point_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + +#endif + + //TODO: if CSEBase returns a reference to a base point, cast it to a + //reference to a wrapper point. Ugly but should be safe. + Point_ source()const{ + return Point_(Eval_functor(),CSEBase(),rep(),0); + } + Point_ target()const{ + return Point_(Eval_functor(),CSEBase(),rep(),1); + } + +}; + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_SEGMENT_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h new file mode 100644 index 00000000..87f0c66e --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h @@ -0,0 +1,130 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_SPHERE_D_H +#define CGAL_WRAPPER_SPHERE_D_H + +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Sphere_d : public Get_type::type +{ + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Point_; + typedef typename Get_functor >::type CSBase; + typedef typename Get_functor::type COSBase; + typedef typename Get_functor::type SRBase; + + typedef Sphere_d Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef typename Increment_dimension::type Feature_dimension; + + typedef typename Get_type::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Sphere_d(U&&...u) + : Rep(CSBase()(std::forward(u)...)){} + +// // called from Construct_point_d +// template explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Sphere_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Point_d(Point_d const&)=default; + Point_d(Point_d &);//=default; + Point_d(Point_d &&)=default; +#endif + + // try not to use these + Sphere_d(Rep const& v) : Rep(v) {} + Sphere_d(Rep& v) : Rep(static_cast(v)) {} + Sphere_d(Rep&& v) : Rep(std::move(v)) {} + +#else + + Sphere_d() : Rep(CSBase()()) {} + + Sphere_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Sphere_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CSBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Sphere_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Point_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + +#endif + + //TODO: if COSBase returns a reference to a base point, cast it to a + //reference to a wrapper point. Ugly but should be safe. + Point_ center()const{ + return Point_(Eval_functor(),COSBase(),rep()); + } + FT_ squared_radius()const{ + return SRBase()(rep()); + } + +}; + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_SPHERE_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h new file mode 100644 index 00000000..b7d1f0d0 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h @@ -0,0 +1,266 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_VECTOR_D_H +#define CGAL_WRAPPER_VECTOR_D_H + +#include +#include +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Vector_d : public Get_type::type +{ + typedef typename Get_type::type RT_; + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Point_; + typedef typename Get_functor >::type CVBase; + typedef typename Get_functor::type CCBase; + typedef typename Get_functor >::type CVI; + typedef typename Get_functor::type SLBase; + + typedef Vector_d Self; + CGAL_static_assertion((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef Dimension_tag<0> Feature_dimension; + + //typedef typename R_::Vector_cartesian_const_iterator Cartesian_const_iterator; + typedef typename Get_type::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Vector_d(U&&...u) + : Rep(CVBase()(std::forward(u)...)){} + +// // called from Construct_vector_d +// template explicit Vector_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Vector_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Vector_d(Vector_d const&)=default; + Vector_d(Vector_d &);//=default; + Vector_d(Vector_d &&)=default; +#endif + + // try not to use these + Vector_d(Rep const& v) : Rep(v) {} + Vector_d(Rep& v) : Rep(static_cast(v)) {} + Vector_d(Rep&& v) : Rep(std::move(v)) {} + + // this one should be implicit + Vector_d(Null_vector const& v) + : Rep(CVBase()(v)) {} + Vector_d(Null_vector& v) + : Rep(CVBase()(v)) {} + Vector_d(Null_vector&& v) + : Rep(CVBase()(std::move(v))) {} + +#else + + Vector_d() : Rep(CVBase()()) {} + + Vector_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Vector_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CVBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Vector_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Vector_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + + // this one should be implicit + Vector_d(Null_vector const& v) + : Rep(CVBase()(v)) {} + +#endif + + typename boost::result_of::type cartesian(int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of::type operator[](int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of::type cartesian_begin()const{ + return CVI()(rep(),Begin_tag()); + } + + typename boost::result_of::type cartesian_end()const{ + return CVI()(rep(),End_tag()); + } + + Vector_d operator-() const + { + return typename Get_functor::type()(*this); + } + + /* + Direction_d direction() const + { + return R().construct_direction_d_object()(*this); + } + + Vector_d transform(const Aff_transformation_d &t) const + { + return t.transform(*this); + } + + Vector_d operator/(const RT& c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + Vector_d operator/(const typename First_if_different::Type & c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + typename Qualified_result_of::type + x() const + { + return R().compute_x_3_object()(*this); + } + + typename Qualified_result_of::type + y() const + { + return R().compute_y_3_object()(*this); + } + + typename Qualified_result_of::type + z() const + { + return R().compute_z_3_object()(*this); + } + + typename Qualified_result_of::type + hx() const + { + return R().compute_hx_3_object()(*this); + } + + typename Qualified_result_of::type + hy() const + { + return R().compute_hy_3_object()(*this); + } + + typename Qualified_result_of::type + hz() const + { + return R().compute_hz_3_object()(*this); + } + + typename Qualified_result_of::type + hw() const + { + return R().compute_hw_3_object()(*this); + } + + typename Qualified_result_of::type + cartesian(int i) const + { + CGAL_kernel_precondition( (i == 0) || (i == 1) || (i == 2) ); + if (i==0) return x(); + if (i==1) return y(); + return z(); + } + + typename Qualified_result_of::type + homogeneous(int i) const + { + CGAL_kernel_precondition( (i >= 0) || (i <= 3) ); + if (i==0) return hx(); + if (i==1) return hy(); + if (i==2) return hz(); + return hw(); + } + + int dimension() const // bad idea? + { + return rep.dimension(); + } +*/ + typename boost::result_of::type squared_length()const{ + return SLBase()(rep()); + } +}; +#if 0 +template Vector_d::Vector_d(Vector_d &)=default; +#endif + +//TODO: IO + +template +Vector_d operator+(const Vector_d& v,const Vector_d& w) +{ + return typename Get_functor::type()(v,w); +} + +template +Vector_d operator-(const Vector_d& v,const Vector_d& w) +{ + return typename Get_functor::type()(v,w); +} + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_VECTOR_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h new file mode 100644 index 00000000..877eea21 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h @@ -0,0 +1,129 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_WRAPPER_WEIGHTED_POINT_D_H +#define CGAL_WRAPPER_WEIGHTED_POINT_D_H + +#include +#include +#include +#include +#include +#ifndef CGAL_CXX11 +#include +#endif +#include + +namespace CGAL { +namespace Wrap { + +template +class Weighted_point_d : public Get_type::type +{ + typedef typename Get_type::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type::type Point_; + typedef typename Get_functor >::type CWPBase; + typedef typename Get_functor::type PDWBase; + typedef typename Get_functor::type PWBase; + + typedef Weighted_point_d Self; + BOOST_STATIC_ASSERT((boost::is_same::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef Dimension_tag<0> Feature_dimension; + + typedef typename Get_type::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template::type...>,std::tuple >::value>::type> explicit Weighted_point_d(U&&...u) + : Rep(CWPBase()(std::forward(u)...)){} + +// // called from Construct_point_d +// template explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward(u)...){} + template explicit Weighted_point_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward(f)(std::forward(u)...)){} + +#if 0 + // the new standard may make this necessary + Point_d(Point_d const&)=default; + Point_d(Point_d &);//=default; + Point_d(Point_d &&)=default; +#endif + + // try not to use these + Weighted_point_d(Rep const& v) : Rep(v) {} + Weighted_point_d(Rep& v) : Rep(static_cast(v)) {} + Weighted_point_d(Rep&& v) : Rep(std::move(v)) {} + +#else + + Weighted_point_d() : Rep(CWPBase()()) {} + + Weighted_point_d(Rep const& v) : Rep(v) {} // try not to use it + +#define CGAL_CODE(Z,N,_) template \ + explicit Weighted_point_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CWPBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template \ + Weighted_point_d(Eval_functor,F const& f,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(f(BOOST_PP_ENUM_PARAMS(N,t))) {} + /* + template \ + Point_d(Eval_functor,BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(Eval_functor(), BOOST_PP_ENUM_PARAMS(N,t)) {} + */ + + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE + +#endif + + //TODO: use references? + Point_ point()const{ + return Point_(Eval_functor(),PDWBase(),rep()); + } + FT_ weight()const{ + return PWBase()(rep()); + } + +}; + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_SPHERE_D_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h b/include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h new file mode 100644 index 00000000..5a132ad2 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h @@ -0,0 +1,1355 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_KERNEL_D_FUNCTION_OBJECTS_CARTESIAN_H +#define CGAL_KERNEL_D_FUNCTION_OBJECTS_CARTESIAN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CGAL_CXX11 +#include +#endif + +namespace CGAL { +namespace CartesianDKernelFunctors { +namespace internal { +template struct Dimension_at_most { enum { value = false }; }; +template struct Dimension_at_most,b> { + enum { value = (a <= b) }; +}; +} + +template::value> struct Orientation_of_points : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename R::LA::Square_matrix Matrix; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type pd(this->kernel()); + Point const& p0=*f++; + int d=pd(p0); + Matrix m(d,d); + // FIXME: this writes the vector coordinates in lines ? check all the other uses in this file, this may be wrong for some. + for(int i=0;f!=e;++f,++i) { + Point const& p=*f; + for(int j=0;j,typename R::Default_ambient_dimension>::value>::type> + template =3)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward(u)...}); + } + + template + result_type operator()(std::initializer_list

l) const { + return operator()(l.begin(),l.end()); + } +#else + //should we make it template to avoid instantiation for wrong dim? + //or iterate outside the class? +#define CGAL_VAR(Z,J,I) m(I,J)=c(p##I,J)-c(x,J); +#define CGAL_VAR2(Z,I,N) BOOST_PP_REPEAT(N,CGAL_VAR,I) +#define CGAL_CODE(Z,N,_) \ + result_type operator()(Point const&x, BOOST_PP_ENUM_PARAMS(N,Point const&p)) const { \ + typename Get_functor::type c(this->kernel()); \ + Matrix m(N,N); \ + BOOST_PP_REPEAT(N,CGAL_VAR2,N) \ + return R::LA::sign_of_determinant(CGAL_MOVE(m)); \ + } + +BOOST_PP_REPEAT_FROM_TO(7, 10, CGAL_CODE, _ ) + // No need to do it for <=6, since that uses a different code path +#undef CGAL_CODE +#undef CGAL_VAR2 +#undef CGAL_VAR +#endif +}; + +#ifdef CGAL_CXX11 +template struct Orientation_of_points,true> : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + templatestruct Help; + templatestruct Help > { + template result_type operator()(C const&c,P const&x,T&&t)const{ + return sign_of_determinant(c(std::get(t),I%d)-c(x,I%d)...); + } + }; + template result_type operator()(P0 const&x,P&&...p)const{ + static_assert(d==sizeof...(P),"Wrong number of arguments"); + typename Get_functor::type c(this->kernel()); + return Help::type>()(c,x,std::forward_as_tuple(std::forward

(p)...)); + } + + + template result_type help2(Dimension_tag, Iter f, Iter const&e, U&&...u)const{ + auto const&p=*f; + return help2(Dimension_tag(),++f,e,std::forward(u)...,p); + } + template result_type help2(Dimension_tag<0>, Iter CGAL_assertion_code(f), Iter const& CGAL_assertion_code(e), U&&...u)const{ + CGAL_assertion(f==e); + return operator()(std::forward(u)...); + } + template + result_type operator()(Iter f, Iter e)const{ + return help2(Dimension_tag(),f,e); + } +}; +#else +#define CGAL_VAR(Z,J,I) c(p##I,J)-x##J +#define CGAL_VAR2(Z,I,N) BOOST_PP_ENUM(N,CGAL_VAR,I) +#define CGAL_VAR3(Z,N,_) Point const&p##N=*++f; +#define CGAL_VAR4(Z,N,_) RT const&x##N=c(x,N); +#define CGAL_CODE(Z,N,_) \ +template struct Orientation_of_points,true> : private Store_kernel { \ + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) \ + typedef R_ R; \ + typedef typename Get_type::type RT; \ + typedef typename Get_type::type Point; \ + typedef typename Get_type::type result_type; \ + result_type operator()(Point const&x, BOOST_PP_ENUM_PARAMS(N,Point const&p)) const { \ + typename Get_functor::type c(this->kernel()); \ + BOOST_PP_REPEAT(N,CGAL_VAR4,) \ + return sign_of_determinant(BOOST_PP_ENUM(N,CGAL_VAR2,N)); \ + } \ + template \ + result_type operator()(Iter f, Iter CGAL_assertion_code(e))const{ \ + Point const&x=*f; \ + BOOST_PP_REPEAT(N,CGAL_VAR3,) \ + CGAL_assertion(++f==e); \ + return operator()(x,BOOST_PP_ENUM_PARAMS(N,p)); \ + } \ +}; + + BOOST_PP_REPEAT_FROM_TO(2, 7, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR4 +#undef CGAL_VAR3 +#undef CGAL_VAR2 +#undef CGAL_VAR + +#endif + +template struct Orientation_of_points,true> : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + result_type operator()(Point const&x, Point const&y) const { + typename Get_functor::type c(this->kernel()); + // No sign_of_determinant(RT) :-( + return CGAL::compare(c(y,0),c(x,0)); + } + template + result_type operator()(Iter f, Iter CGAL_assertion_code(e))const{ + Point const&x=*f; + Point const&y=*++f; + CGAL_assertion(++f==e); + return operator()(x,y); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Orientation_of_points_tag,(CartesianDKernelFunctors::Orientation_of_points),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Orientation_of_vectors : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_vectors) + typedef R_ R; + typedef typename Get_type::type Vector; + typedef typename Get_type::type result_type; + typedef typename R::LA::Square_matrix Matrix; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type vd(this->kernel()); + // FIXME: Uh? Using it on a vector ?! + Vector const& v0=*f; + int d=vd(v0); + Matrix m(d,d); + for(int j=0;j=3)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward(u)...}); + } + + template + result_type operator()(std::initializer_list l) const { + return operator()(l.begin(),l.end()); + } +#else + //TODO +#endif +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Orientation_of_vectors_tag,(CartesianDKernelFunctors::Orientation_of_vectors),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Linear_rank : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Linear_rank) + typedef R_ R; + typedef typename Get_type::type Vector; + // Computing a sensible Uncertain is not worth it + typedef int result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type vd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + if (n==0) return 0; + Vector const& v0 = *f; + // FIXME: Uh? Using it on a vector ?! + int d=vd(v0); + Matrix m(d,n); + for(int j=0;j),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Linearly_independent : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Linearly_independent) + typedef R_ R; + typedef typename Get_type::type result_type; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type vd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + // FIXME: Uh? Using it on a vector ?! + int d=vd(*f); + if (n>d) return false; + typename Get_functor::type lr(this->kernel()); + return lr(f,e) == n; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Linearly_independent_tag,(CartesianDKernelFunctors::Linearly_independent),(Vector_tag),(Point_dimension_tag,Linear_rank_tag)); + +namespace CartesianDKernelFunctors { +template struct Contained_in_linear_hull : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Contained_in_linear_hull) + typedef R_ R; + typedef typename Get_type::type Vector; + // Computing a sensible Uncertain is not worth it + typedef bool result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template + result_type operator()(Iter f, Iter e,V const&w)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type vd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + if (n==0) return false; + // FIXME: Uh? Using it on a vector ?! + int d=vd(w); + Matrix m(d,n+1); + for(int i=0; f!=e; ++f,++i){ + Vector const& v = *f; + for(int j=0;j),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Affine_rank : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Affine_rank) + typedef R_ R; + typedef typename Get_type::type Point; + // Computing a sensible Uncertain is not worth it + typedef int result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type pd(this->kernel()); + int n=(int)std::distance(f,e); + if (--n<=0) return n; + Point const& p0 = *f; + int d=pd(p0); + Matrix m(d,n); + for(int i=0; ++f!=e; ++i){ + Point const& p = *f; + for(int j=0;j),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Affinely_independent : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Affinely_independent) + typedef R_ R; + typedef typename Get_type::type result_type; + + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type pd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + int d=pd(*f); + if (--n>d) return false; + typename Get_functor::type ar(this->kernel()); + return ar(f,e) == n; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Affinely_independent_tag,(CartesianDKernelFunctors::Affinely_independent),(Point_tag),(Point_dimension_tag,Affine_rank_tag)); + +namespace CartesianDKernelFunctors { +template struct Contained_in_simplex : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Contained_in_simplex) + typedef R_ R; + typedef typename Get_type::type Point; + // Computing a sensible Uncertain<*> is not worth it + // typedef typename Get_type::type result_type; + typedef bool result_type; + typedef typename Increment_dimension::type D1; + typedef typename Increment_dimension::type D2; + typedef typename R::LA::template Rebind_dimension::Other LA; + typedef typename LA::Dynamic_matrix Matrix; + typedef typename LA::Dynamic_vector DynVec; + typedef typename LA::Vector Vec; + + template + result_type operator()(Iter f, Iter e, P const&q)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type pd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + if (n==0) return false; + int d=pd(q); + Matrix m(d+1,n); + DynVec a(n); + // FIXME: Should use the proper vector constructor (Iterator_and_last) + Vec b(d+1); + for(int j=0;j),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { + namespace internal { + template + struct Matrix_col_access { + typedef Ref_ result_type; + int col; + Matrix_col_access(int r):col(r){} + template Ref_ operator()(Mat const& m, std::ptrdiff_t row)const{ + return m(row,col); + } + }; + } +template struct Linear_base : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Linear_base) + typedef R_ R; + typedef typename Get_type::type Vector; + typedef typename Get_type::type FT; + typedef void result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template + result_type operator()(Iter f, Iter e, Oter&o)const{ + typename Get_functor::type c(this->kernel()); + typename Get_functor::type vd(this->kernel()); + typename Get_functor >::type cv(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + if (n==0) return; + Vector const& v0 = *f; + // FIXME: Uh? Using it on a vector ?! + int d=vd(v0); + Matrix m(d,n); + for(int j=0;j()(0,0)) +#else + FT +#endif + Ref; + typedef Iterator_from_indices > IFI; + *o++ = cv(IFI(b,0,i),IFI(b,d,i)); + } + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Linear_base_tag,(CartesianDKernelFunctors::Linear_base),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +#if 0 +namespace CartesianDKernelFunctors { +template::value> struct Orientation : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation) + typedef R_ R; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type OP; + typedef typename Get_functor::type OV; + + //FIXME!!! + //when Point and Vector are distinct types, the dispatch should be made + //in a way that doesn't instantiate a conversion from Point to Vector + template + result_type operator()(Iter const&f, Iter const& e)const{ + typename Get_functor::type pd(this->kernel()); + typename std::iterator_traits::difference_type d=std::distance(f,e); + int dim=pd(*f); // BAD + if(d==dim) return OV(this->kernel())(f,e); + CGAL_assertion(d==dim+1); + return OP(this->kernel())(f,e); + } + //TODO: version that takes objects directly instead of iterators +}; + +template struct Orientation : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Orientation) + typedef R_ R; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type OP; + typedef typename Get_functor::type OV; + typedef typename R::LA::Square_matrix Matrix; + + //FIXME!!! + //when Point and Vector are distinct types, the dispatch should be made + //in a way that doesn't instantiate a conversion from Point to Vector + template + typename boost::enable_if,result_type>::type + operator()(Iter const&f, Iter const& e)const{ + return OP(this->kernel())(f,e); + } + template + typename boost::enable_if,result_type>::type + operator()(Iter const&f, Iter const& e)const{ + return OV(this->kernel())(f,e); + } + //TODO: version that takes objects directly instead of iterators +}; +} +#endif + +namespace CartesianDKernelFunctors { +template struct Power_side_of_power_sphere_raw : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Power_side_of_power_sphere_raw) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type FT; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename Increment_dimension::type D1; + typedef typename Increment_dimension::type D2; + typedef typename R::LA::template Rebind_dimension::Other LA; + typedef typename LA::Square_matrix Matrix; + + template + result_type operator()(IterP f, IterP const& e, IterW fw, Pt const& p0, Wt const& w0) const { + typedef typename Get_functor::type Sqdo; + typename Get_functor::type c(this->kernel()); + typename Get_functor::type pd(this->kernel()); + + int d=pd(p0); + Matrix m(d+1,d+1); + if(CGAL::Is_stored::value) { + Sqdo sqdo(this->kernel()); + FT const& h0 = sqdo(p0) - w0; + for(int i=0;f!=e;++f,++fw,++i) { + Point const& p=*f; + for(int j=0;j),(Point_tag),(Point_dimension_tag,Squared_distance_to_origin_tag,Compute_point_cartesian_coordinate_tag)); + +// TODO: make Side_of_oriented_sphere call Power_side_of_power_sphere_raw +namespace CartesianDKernelFunctors { +template struct Side_of_oriented_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Side_of_oriented_sphere) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + typedef typename Increment_dimension::type D1; + typedef typename Increment_dimension::type D2; + typedef typename R::LA::template Rebind_dimension::Other LA; + typedef typename LA::Square_matrix Matrix; + + template + result_type operator()(Iter f, Iter const& e)const{ + Point const& p0=*f++; // *--e ? + return this->operator()(f,e,p0); + } + + template + result_type operator()(Iter f, Iter const& e, Point const& p0) const { + typedef typename Get_functor::type Sqdo; + typename Get_functor::type c(this->kernel()); + typename Get_functor::type pd(this->kernel()); + + int d=pd(p0); + Matrix m(d+1,d+1); + if(CGAL::Is_stored::value) { + Sqdo sqdo(this->kernel()); + for(int i=0;f!=e;++f,++i) { + Point const& p=*f; + for(int j=0;j=4)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward(u)...}); + } + + template + result_type operator()(std::initializer_list

l) const { + return operator()(l.begin(),l.end()); + } +#else + //TODO +#endif +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Side_of_oriented_sphere_tag,(CartesianDKernelFunctors::Side_of_oriented_sphere),(Point_tag),(Point_dimension_tag,Squared_distance_to_origin_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Construct_circumcenter : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Construct_circumcenter) + typedef typename Get_type::type Point; + typedef Point result_type; + typedef typename Get_type::type FT; + template + result_type operator()(Iter f, Iter e)const{ + typedef typename Get_type::type Point; + typedef typename R_::LA LA; + typename Get_functor::type c(this->kernel()); + typename Get_functor >::type cp(this->kernel()); + typename Get_functor::type pd(this->kernel()); + typename Get_functor::type sdo(this->kernel()); + + Point const& p0=*f; + int d = pd(p0); + if (d+1 == std::distance(f,e)) + { + // 2*(x-y).c == x^2-y^2 + typedef typename LA::Square_matrix Matrix; + typedef typename LA::Vector Vec; + typedef typename LA::Construct_vector CVec; + FT const& n0 = sdo(p0); + Matrix m(d,d); + Vec b = typename CVec::Dimension()(d); + // Write the point coordinates in lines. + int i; + for(i=0; ++f!=e; ++i) { + Point const& p=*f; + for(int j=0;j::Other LAd; + typedef typename LAd::Square_matrix Matrix; + typedef typename LAd::Vector Vec; + typename Get_functor::type sp(this->kernel()); + int k=static_cast(std::distance(f,e)); + Matrix m(k,k); + Vec b(k); + Vec l(k); + int j,i=0; + for(Iter f2=f;f2!=e;++f2,++i){ + b(i)=m(i,i)=sdo(*f2); + j=0; + for(Iter f3=f;f3!=e;++f3,++j){ + m(j,i)=m(i,j)=sp(*f2,*f3); + } + } + for(i=1;i),(Point_tag),(Construct_ttag,Compute_point_cartesian_coordinate_tag,Scalar_product_tag,Squared_distance_to_origin_tag,Point_dimension_tag)); + +namespace CartesianDKernelFunctors { +template struct Squared_circumradius : Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Squared_circumradius) + typedef typename Get_type::type result_type; + template + result_type operator()(Iter f, Iter e)const{ + typename Get_functor::type cc(this->kernel()); + typename Get_functor::type sd(this->kernel()); + return sd(cc(f, e), *f); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Squared_circumradius_tag,(CartesianDKernelFunctors::Squared_circumradius),(Point_tag),(Construct_circumcenter_tag,Squared_distance_tag)); + +namespace CartesianDKernelFunctors { +// TODO: implement it directly, it should be at least as fast as Side_of_oriented_sphere. +template struct Side_of_bounded_sphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Side_of_bounded_sphere) + typedef R_ R; + typedef typename Get_type::type Point; + typedef typename Get_type::type result_type; + + template + result_type operator()(Iter f, Iter const& e) const { + Point const& p0 = *f++; // *--e ? + typename Get_functor::type pd(this->kernel()); + //FIXME: Doesn't work for non-full dimension. + CGAL_assertion (std::distance(f,e) == pd(p0)+1); + return operator() (f, e, p0); + } + + template + result_type operator()(Iter const& f, Iter const& e, Point const& p0) const { + typename Get_functor::type sos (this->kernel()); + typename Get_functor::type op (this->kernel()); + // enum_cast is not very generic, but since this function isn't supposed to remain like this... + return enum_cast (sos (f, e, p0) * op (f, e)); + } + +#ifdef CGAL_CXX11 + template =4)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward(u)...}); + } + + template + result_type operator()(std::initializer_list

l) const { + return operator()(l.begin(),l.end()); + } +#else + //TODO +#endif +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Side_of_bounded_sphere_tag,(CartesianDKernelFunctors::Side_of_bounded_sphere),(Point_tag),(Side_of_oriented_sphere_tag,Orientation_of_points_tag)); + +namespace CartesianDKernelFunctors { +template struct Side_of_bounded_circumsphere : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Side_of_bounded_circumsphere) + typedef typename Get_type::type result_type; + + template + result_type operator()(Iter f, Iter const& e, P const& p0) const { + // TODO: Special case when the dimension is full. + typename Get_functor::type cc(this->kernel()); + typename Get_functor::type cd(this->kernel()); + + return enum_cast(cd(cc(f, e), *f, p0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Side_of_bounded_circumsphere_tag,(CartesianDKernelFunctors::Side_of_bounded_circumsphere),(Point_tag),(Squared_distance_tag,Construct_circumcenter_tag)); + +namespace CartesianDKernelFunctors { +template struct Point_to_vector : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Point_to_vector) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Point argument_type; + result_type operator()(argument_type const&v)const{ + CI ci(this->kernel()); + return CV(this->kernel())(ci(v,Begin_tag()),ci(v,End_tag())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Point_to_vector_tag,(CartesianDKernelFunctors::Point_to_vector),(Point_tag,Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Vector_to_point : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Vector_to_point) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CP; + typedef typename Get_functor >::type CI; + typedef Point result_type; + typedef Vector argument_type; + result_type operator()(argument_type const&v)const{ + CI ci(this->kernel()); + return CP(this->kernel())(ci(v,Begin_tag()),ci(v,End_tag())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Vector_to_point_tag,(CartesianDKernelFunctors::Vector_to_point),(Point_tag,Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Opposite_vector : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Opposite_vector) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Vector argument_type; + result_type operator()(Vector const&v)const{ + CI ci(this->kernel()); + return CV(this->kernel())(make_transforming_iterator(ci(v,Begin_tag()),std::negate()),make_transforming_iterator(ci(v,End_tag()),std::negate())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Opposite_vector_tag,(CartesianDKernelFunctors::Opposite_vector),(Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Scaled_vector : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Scaled_vector) + typedef R_ R; + typedef typename Get_type::type FT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Vector first_argument_type; + typedef FT second_argument_type; + result_type operator()(Vector const&v,FT const& s)const{ + CI ci(this->kernel()); + return CV(this->kernel())(make_transforming_iterator(ci(v,Begin_tag()),Scale(s)),make_transforming_iterator(ci(v,End_tag()),Scale(s))); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Scaled_vector_tag,(CartesianDKernelFunctors::Scaled_vector),(Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Sum_of_vectors : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Sum_of_vectors) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Vector first_argument_type; + typedef Vector second_argument_type; + result_type operator()(Vector const&a, Vector const&b)const{ + CI ci(this->kernel()); + return CV(this->kernel())(make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),std::plus()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::plus())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Sum_of_vectors_tag,(CartesianDKernelFunctors::Sum_of_vectors),(Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Difference_of_vectors : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Difference_of_vectors) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Vector first_argument_type; + typedef Vector second_argument_type; + result_type operator()(Vector const&a, Vector const&b)const{ + CI ci(this->kernel()); + return CV(this->kernel())(make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),std::minus()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::minus())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Difference_of_vectors_tag,(CartesianDKernelFunctors::Difference_of_vectors),(Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Translated_point : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Translated_point) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CP; + typedef typename Get_functor >::type CVI; + typedef typename Get_functor >::type CPI; + typedef Point result_type; + typedef Point first_argument_type; + typedef Vector second_argument_type; + result_type operator()(Point const&a, Vector const&b)const{ + CVI cvi(this->kernel()); + CPI cpi(this->kernel()); + return CP(this->kernel())(make_transforming_pair_iterator(cpi(a,Begin_tag()),cvi(b,Begin_tag()),std::plus()),make_transforming_pair_iterator(cpi(a,End_tag()),cvi(b,End_tag()),std::plus())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Translated_point_tag,(CartesianDKernelFunctors::Translated_point),(Point_tag, Vector_tag),(Construct_ttag, Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Difference_of_points : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Difference_of_points) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CV; + typedef typename Get_functor >::type CI; + typedef Vector result_type; + typedef Point first_argument_type; + typedef Point second_argument_type; + result_type operator()(Point const&a, Point const&b)const{ + CI ci(this->kernel()); + return CV(this->kernel())(make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),std::minus()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::minus())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Difference_of_points_tag,(CartesianDKernelFunctors::Difference_of_points),(Point_tag, Vector_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Midpoint : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Midpoint) + typedef R_ R; + typedef typename Get_type::type FT; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CP; + typedef typename Get_functor >::type CI; + typedef Point result_type; + typedef Point first_argument_type; + typedef Point second_argument_type; + // There is a division, but it will be cast to RT afterwards anyway, so maybe we could use RT. + struct Average : std::binary_function { + FT operator()(FT const&a, RT const&b)const{ + return (a+b)/2; + } + }; + result_type operator()(Point const&a, Point const&b)const{ + CI ci(this->kernel()); + //Divide half(2); + //return CP(this->kernel())(make_transforming_iterator(make_transforming_pair_iterator(ci.begin(a),ci.begin(b),std::plus()),half),make_transforming_iterator(make_transforming_pair_iterator(ci.end(a),ci.end(b),std::plus()),half)); + return CP(this->kernel())(make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),Average()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),Average())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Midpoint_tag,(CartesianDKernelFunctors::Midpoint),(Point_tag),(Construct_ttag, Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Squared_length : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Squared_length) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CI; + typedef RT result_type; + typedef Vector argument_type; + result_type operator()(Vector const&a)const{ + CI ci(this->kernel()); + typename Algebraic_structure_traits::Square f; + // TODO: avoid this RT(0)+... + return std::accumulate(make_transforming_iterator(ci(a,Begin_tag()),f),make_transforming_iterator(ci(a,End_tag()),f),RT(0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Squared_length_tag,(CartesianDKernelFunctors::Squared_length),(Vector_tag),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Squared_distance_to_origin : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Squared_distance_to_origin) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CI; + typedef RT result_type; + typedef Point argument_type; + result_type operator()(Point const&a)const{ + CI ci(this->kernel()); + typename Algebraic_structure_traits::Square f; + // TODO: avoid this RT(0)+... + return std::accumulate(make_transforming_iterator(ci(a,Begin_tag()),f),make_transforming_iterator(ci(a,End_tag()),f),RT(0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Squared_distance_to_origin_tag,(CartesianDKernelFunctors::Squared_distance_to_origin),(Point_tag),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Squared_distance : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Squared_distance) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Point; + typedef typename Get_functor >::type CI; + typedef RT result_type; + typedef Point first_argument_type; + typedef Point second_argument_type; + struct Sq_diff : std::binary_function { + RT operator()(RT const&a, RT const&b)const{ + return CGAL::square(a-b); + } + }; + result_type operator()(Point const&a, Point const&b)const{ + CI ci(this->kernel()); + Sq_diff f; + // TODO: avoid this RT(0)+... + return std::accumulate(make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),f),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),f),RT(0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Squared_distance_tag,(CartesianDKernelFunctors::Squared_distance),(Point_tag),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Scalar_product : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Scalar_product) + typedef R_ R; + typedef typename Get_type::type RT; + typedef typename Get_type::type Vector; + typedef typename Get_functor >::type CI; + typedef RT result_type; + typedef Vector first_argument_type; + typedef Vector second_argument_type; + result_type operator()(Vector const&a, Vector const&b)const{ + CI ci(this->kernel()); + std::multiplies f; + // TODO: avoid this RT(0)+... + return std::accumulate( + make_transforming_pair_iterator(ci(a,Begin_tag()),ci(b,Begin_tag()),f), + make_transforming_pair_iterator(ci(a, End_tag()),ci(b, End_tag()),f), + RT(0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Scalar_product_tag,(CartesianDKernelFunctors::Scalar_product),(Vector_tag),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Compare_distance : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Compare_distance) + typedef R_ R; + typedef typename Get_type::type Point; + typedef typename Get_functor::type CSD; + typedef typename Get_type::type result_type; + typedef Point first_argument_type; + typedef Point second_argument_type; + typedef Point third_argument_type; // why am I doing this already? + typedef Point fourth_argument_type; + result_type operator()(Point const&a, Point const&b, Point const&c)const{ + CSD csd(this->kernel()); + return CGAL_NTS compare(csd(a,b),csd(a,c)); + } + result_type operator()(Point const&a, Point const&b, Point const&c, Point const&d)const{ + CSD csd(this->kernel()); + return CGAL_NTS compare(csd(a,b),csd(c,d)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Compare_distance_tag,(CartesianDKernelFunctors::Compare_distance),(Point_tag),(Squared_distance_tag)); + +namespace CartesianDKernelFunctors { +template struct Less_point_cartesian_coordinate : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Less_point_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type Cc; + // TODO: This is_exact thing should be reengineered. + // the goal is to have a way to tell: don't filter this + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator()(V const&a, W const&b, I i)const{ + Cc c(this->kernel()); + return c(a,i)),(),(Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Compare_point_cartesian_coordinate : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Compare_point_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type Cc; + // TODO: This is_exact thing should be reengineered. + // the goal is to have a way to tell: don't filter this + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator()(V const&a, W const&b, I i)const{ + Cc c(this->kernel()); + return CGAL_NTS compare(c(a,i),c(b,i)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Compare_point_cartesian_coordinate_tag,(CartesianDKernelFunctors::Compare_point_cartesian_coordinate),(),(Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template struct Compare_lexicographically : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Compare_lexicographically) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor >::type CI; + // TODO: This is_exact thing should be reengineered. + // the goal is to have a way to tell: don't filter this + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator()(V const&a, W const&b)const{ + CI c(this->kernel()); +#ifdef CGAL_CXX11 + auto +#else + typename CI::result_type +#endif + a_begin=c(a,Begin_tag()), + b_begin=c(b,Begin_tag()), + a_end=c(a,End_tag()); + result_type res; + // can't we do slightly better for Uncertain<*> ? + // after res=...; if(is_uncertain(res))return indeterminate(); + do res=CGAL_NTS compare(*a_begin++,*b_begin++); + while(a_begin!=a_end && res==EQUAL); + return res; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Compare_lexicographically_tag,(CartesianDKernelFunctors::Compare_lexicographically),(),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Less_lexicographically : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Less_lexicographically) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type CL; + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator() (V const&a, W const&b) const { + CL c (this->kernel()); + return c(a,b) < 0; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Less_lexicographically_tag,(CartesianDKernelFunctors::Less_lexicographically),(),(Compare_lexicographically_tag)); + +namespace CartesianDKernelFunctors { +template struct Less_or_equal_lexicographically : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Less_or_equal_lexicographically) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type CL; + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator() (V const&a, W const&b) const { + CL c (this->kernel()); + return c(a,b) <= 0; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Less_or_equal_lexicographically_tag,(CartesianDKernelFunctors::Less_or_equal_lexicographically),(),(Compare_lexicographically_tag)); + +namespace CartesianDKernelFunctors { +template struct Equal_points : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Equal_points) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor >::type CI; + // TODO: This is_exact thing should be reengineered. + // the goal is to have a way to tell: don't filter this + typedef typename CGAL::Is_exact Is_exact; + + template + result_type operator()(V const&a, W const&b)const{ + CI c(this->kernel()); +#ifdef CGAL_CXX11 + auto +#else + typename CI::result_type +#endif + a_begin=c(a,Begin_tag()), + b_begin=c(b,Begin_tag()), + a_end=c(a,End_tag()); + result_type res = true; + // Is using CGAL::possibly for Uncertain really an optimization? + do res = res & (*a_begin++ == *b_begin++); + while(a_begin!=a_end && possibly(res)); + return res; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Equal_points_tag,(CartesianDKernelFunctors::Equal_points),(),(Construct_ttag)); + +namespace CartesianDKernelFunctors { +template struct Oriented_side : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Oriented_side) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_type::type Point; + typedef typename Get_type::type Hyperplane; + typedef typename Get_type::type Sphere; + typedef typename Get_functor::type VA; + typedef typename Get_functor::type HT; + typedef typename Get_functor::type SD; + typedef typename Get_functor::type SR; + typedef typename Get_functor::type CS; + + result_type operator()(Hyperplane const&h, Point const&p)const{ + HT ht(this->kernel()); + VA va(this->kernel()); + return CGAL::compare(va(h,p),ht(h)); + } + result_type operator()(Sphere const&s, Point const&p)const{ + SD sd(this->kernel()); + SR sr(this->kernel()); + CS cs(this->kernel()); + return CGAL::compare(sd(cs(s),p),sr(s)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Oriented_side_tag,(CartesianDKernelFunctors::Oriented_side),(Point_tag,Sphere_tag,Hyperplane_tag),(Value_at_tag,Hyperplane_translation_tag,Squared_distance_tag,Squared_radius_tag,Center_of_sphere_tag)); + +namespace CartesianDKernelFunctors { +template struct Has_on_positive_side : private Store_kernel { + CGAL_FUNCTOR_INIT_STORE(Has_on_positive_side) + typedef R_ R; + typedef typename Get_type::type result_type; + typedef typename Get_functor::type OS; + + template + result_type operator()(Obj const&o, Pt const&p)const{ + OS os(this->kernel()); + return os(o,p) == ON_POSITIVE_SIDE; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Has_on_positive_side_tag,(CartesianDKernelFunctors::Has_on_positive_side),(),(Oriented_side_tag)); + +} +#include +#endif // CGAL_KERNEL_D_FUNCTION_OBJECTS_CARTESIAN_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h b/include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h new file mode 100644 index 00000000..c25c4e2b --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_EXACTNESS_H +#define CGAL_EXACTNESS_H +#include +#include +namespace CGAL { + +#define CGAL_STRAWBERRY(Is_pretty) \ + namespace internal { \ + BOOST_MPL_HAS_XXX_TRAIT_DEF(Is_pretty) \ + } \ + template::value> \ + struct Is_pretty : boost::false_type {}; \ + template \ + struct Is_pretty : T::Is_pretty {} + +CGAL_STRAWBERRY(Is_exact); +CGAL_STRAWBERRY(Is_fast); +CGAL_STRAWBERRY(Is_stored); +#undef CGAL_STRAWBERRY +} +#endif // CGAL_EXACTNESS_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h b/include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h new file mode 100644 index 00000000..b8e17886 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h @@ -0,0 +1,363 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_FUNCTOR_TAGS_H +#define CGAL_FUNCTOR_TAGS_H +#include // for Null_tag +#include +#ifdef CGAL_CXX11 +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +namespace CGAL { + + // Find a better place for this later + + template struct Get_type + : K::template Type {}; + template struct Get_functor + : K::template Functor {}; +#ifdef CGAL_CXX11 + template using Type = typename Get_type::type; + template using Functor = typename Get_functor::type; +#endif + + class Null_type {~Null_type();}; // no such object should be created + + // To construct iterators + struct Begin_tag {}; + struct End_tag {}; + + // Functor category + struct Predicate_tag {}; + struct Construct_tag {}; + struct Construct_iterator_tag {}; + struct Compute_tag {}; + struct Misc_tag {}; + + struct No_filter_tag {}; + + templatestruct Construct_ttag {}; + templatestruct Convert_ttag {}; + + template struct Get_functor_category { typedef Misc_tag type; }; + template struct Typedef_tag_type; + //template struct Read_tag_type {}; + + template + struct Provides_type + : Has_type_different_from, Null_type> {}; + + template + struct Provides_functor + : Has_type_different_from, Null_functor> {}; + + template::type::value> + struct Provides_functors : boost::mpl::and_ < + Provides_functor::type>, + Provides_functors::type> > {}; + template + struct Provides_functors : boost::true_type {}; + + template::type::value> + struct Provides_types : boost::mpl::and_ < + Provides_type::type>, + Provides_types::type> > {}; + template + struct Provides_types : boost::true_type {}; + + namespace internal { BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_Type,template Type,false) } + template::value /* false */> + struct Provides_type_i : boost::false_type {}; + template + struct Provides_type_i + : Has_type_different_from, Null_type> {}; + + //// This version does not like Functor + //namespace internal { BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_Functor,Functor,false) } + // This version lets us use non-type template parameters, but fails with older EDG-based compilers (Intel 14). + namespace internal { BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_Functor,template Functor,false) } + + template::value /* false */> + struct Provides_functor_i : boost::false_type {}; + template + struct Provides_functor_i + : Has_type_different_from, Null_functor> {}; + + // TODO: Refine this a bit. + template ::value, + //bool=Provides_functor_i::value, + bool = internal::has_Functor::value + > + struct Inherit_functor : K::template Functor {}; + template + struct Inherit_functor {}; + + template ::value> + struct Inherit_type : K::template Type {}; + template + struct Inherit_type {}; + + struct Number_tag {}; + struct Discrete_tag {}; + struct Object_tag {}; + template struct Get_type_category { + // The lazy kernel uses it too eagerly, + // so it currently needs a default. + typedef Null_tag type; + }; + +#define CGAL_DECL_OBJ_(X,Y) \ + template \ + struct Typedef_tag_type : Base { typedef Obj X; }; \ + template \ + struct Get_type_category { typedef Y##_tag type; } +#define CGAL_DECL_OBJ(X,Y) struct X##_tag {}; \ + CGAL_DECL_OBJ_(X,Y) + + //namespace has_object { BOOST_MPL_HAS_XXX_TRAIT_DEF(X) } + //template + //struct Provides_tag_type : has_object::has_##X {}; + //template + //struct Read_tag_type { typedef typename Kernel::X type; } + + // Not exactly objects, but the extras can't hurt. + CGAL_DECL_OBJ(FT, Number); + CGAL_DECL_OBJ(RT, Number); + + CGAL_DECL_OBJ(Bool, Discrete); // Boolean_tag is already taken, and is a template :-( + CGAL_DECL_OBJ(Comparison_result, Discrete); + CGAL_DECL_OBJ(Sign, Discrete); + CGAL_DECL_OBJ(Orientation, Discrete); // Note: duplicate with the functor tag! + CGAL_DECL_OBJ(Oriented_side, Discrete); + CGAL_DECL_OBJ(Bounded_side, Discrete); + CGAL_DECL_OBJ(Angle, Discrete); + CGAL_DECL_OBJ(Flat_orientation, Discrete); + + CGAL_DECL_OBJ(Vector, Object); + CGAL_DECL_OBJ(Point, Object); + CGAL_DECL_OBJ(Segment, Object); + CGAL_DECL_OBJ(Sphere, Object); + CGAL_DECL_OBJ(Line, Object); + CGAL_DECL_OBJ(Direction, Object); + CGAL_DECL_OBJ(Hyperplane, Object); + CGAL_DECL_OBJ(Ray, Object); + CGAL_DECL_OBJ(Iso_box, Object); + CGAL_DECL_OBJ(Bbox, Object); + CGAL_DECL_OBJ(Aff_transformation, Object); + CGAL_DECL_OBJ(Weighted_point, Object); +#undef CGAL_DECL_OBJ_ +#undef CGAL_DECL_OBJ + +// Intel fails with those, and they are not so useful. +// CGAL_KD_DEFAULT_TYPE(RT_tag,(typename Get_type::type),(),()); +// CGAL_KD_DEFAULT_TYPE(FT_tag,(CGAL::Quotient::type>),(),()); + +#define CGAL_SMURF2(A,B) CGAL_KD_DEFAULT_TYPE(A##_tag,(typename Same_uncertainty_nt::type>::type),(RT_tag),()) +#define CGAL_SMURF1(A) CGAL_SMURF2(A,CGAL::A) + CGAL_SMURF2(Bool, bool); + CGAL_SMURF1(Sign); + CGAL_SMURF1(Comparison_result); + CGAL_SMURF1(Orientation); + CGAL_SMURF1(Oriented_side); + CGAL_SMURF1(Bounded_side); + CGAL_SMURF1(Angle); +#undef CGAL_SMURF1 +#undef CGAL_SMURF2 + + // TODO: replace with Get_type_category + template struct is_NT_tag { enum { value = false }; }; + template<> struct is_NT_tag { enum { value = true }; }; + template<> struct is_NT_tag { enum { value = true }; }; + + template struct iterator_tag_traits { + enum { is_iterator = false, has_nth_element = false }; + typedef Null_tag value_tag; + }; + +#define CGAL_DECL_COMPUTE(X) struct X##_tag {}; \ + templatestruct Get_functor_category{typedef Compute_tag type;} + CGAL_DECL_COMPUTE(Compute_point_cartesian_coordinate); + CGAL_DECL_COMPUTE(Compute_vector_cartesian_coordinate); + CGAL_DECL_COMPUTE(Compute_homogeneous_coordinate); + CGAL_DECL_COMPUTE(Squared_distance); + CGAL_DECL_COMPUTE(Squared_distance_to_origin); + CGAL_DECL_COMPUTE(Squared_length); + CGAL_DECL_COMPUTE(Squared_radius); + CGAL_DECL_COMPUTE(Squared_circumradius); + CGAL_DECL_COMPUTE(Scalar_product); + CGAL_DECL_COMPUTE(Hyperplane_translation); + CGAL_DECL_COMPUTE(Value_at); + CGAL_DECL_COMPUTE(Point_weight); + CGAL_DECL_COMPUTE(Power_distance); + CGAL_DECL_COMPUTE(Power_distance_to_point); +#undef CGAL_DECL_COMPUTE + +#define CGAL_DECL_ITER_OBJ(X,Y,Z,C) struct X##_tag {}; \ + template<>struct iterator_tag_traits { \ + enum { is_iterator = true, has_nth_element = true }; \ + typedef Y##_tag value_tag; \ + typedef Z##_tag nth_element; \ + typedef C##_tag container; \ + }; \ + template \ + struct Typedef_tag_type : Base { typedef Obj X; } + + //namespace has_object { BOOST_MPL_HAS_XXX_TRAIT_DEF(X) } + //template + //struct Provides_tag_type : has_object::has_##X {}; + //template + //struct Read_tag_type { typedef typename Kernel::X type; } + + CGAL_DECL_ITER_OBJ(Vector_cartesian_const_iterator, FT, Compute_vector_cartesian_coordinate, Vector); + CGAL_DECL_ITER_OBJ(Point_cartesian_const_iterator, FT, Compute_point_cartesian_coordinate, Point); +#undef CGAL_DECL_ITER_OBJ + + templatestruct map_result_tag{typedef Null_type type;}; + templatestruct map_result_tag >{typedef T type;}; + + templatestruct Get_functor_category,B,C> : + boost::mpl::if_c::is_iterator, + Construct_iterator_tag, + Construct_tag> {}; + + // Really? + templatestruct Get_functor_category,B,C>{typedef Misc_tag type;}; + +#define CGAL_DECL_CONSTRUCT(X,Y) struct X##_tag {}; \ + template<>struct map_result_tag{typedef Y##_tag type;}; \ + templatestruct Get_functor_category{typedef Construct_tag type;} + CGAL_DECL_CONSTRUCT(Midpoint,Point); + CGAL_DECL_CONSTRUCT(Center_of_sphere,Point); + CGAL_DECL_CONSTRUCT(Point_of_sphere,Point); + CGAL_DECL_CONSTRUCT(Segment_extremity,Point); + CGAL_DECL_CONSTRUCT(Sum_of_vectors,Vector); + CGAL_DECL_CONSTRUCT(Difference_of_vectors,Vector); + CGAL_DECL_CONSTRUCT(Opposite_vector,Vector); + CGAL_DECL_CONSTRUCT(Scaled_vector,Vector); + CGAL_DECL_CONSTRUCT(Orthogonal_vector,Vector); + CGAL_DECL_CONSTRUCT(Difference_of_points,Vector); + CGAL_DECL_CONSTRUCT(Translated_point,Point); + CGAL_DECL_CONSTRUCT(Point_to_vector,Vector); + CGAL_DECL_CONSTRUCT(Vector_to_point,Point); + CGAL_DECL_CONSTRUCT(Construct_min_vertex,Point); + CGAL_DECL_CONSTRUCT(Construct_max_vertex,Point); + CGAL_DECL_CONSTRUCT(Construct_circumcenter,Point); + CGAL_DECL_CONSTRUCT(Point_drop_weight,Point); + CGAL_DECL_CONSTRUCT(Power_center,Weighted_point); +#undef CGAL_DECL_CONSTRUCT +#if 0 +#define CGAL_DECL_ITER_CONSTRUCT(X,Y) struct X##_tag {}; \ + template<>struct map_result_tag{typedef Y##_tag type;}; \ + template<>struct map_functor_type{typedef Construct_iterator_tag type;} + CGAL_DECL_ITER_CONSTRUCT(Construct_point_cartesian_const_iterator,Point_cartesian_const_iterator); + CGAL_DECL_ITER_CONSTRUCT(Construct_vector_cartesian_const_iterator,Vector_cartesian_const_iterator); +#undef CGAL_DECL_ITER_CONSTRUCT +#endif + + //FIXME: choose a convention: prefix with Predicate_ ? +#define CGAL_DECL_PREDICATE_(X) \ + templatestruct Get_functor_category{typedef Predicate_tag type;} +#define CGAL_DECL_PREDICATE(X) struct X##_tag {}; \ + CGAL_DECL_PREDICATE_(X) + CGAL_DECL_PREDICATE(Less_point_cartesian_coordinate); + CGAL_DECL_PREDICATE(Compare_point_cartesian_coordinate); + CGAL_DECL_PREDICATE(Compare_distance); + CGAL_DECL_PREDICATE(Compare_lexicographically); + CGAL_DECL_PREDICATE(Less_lexicographically); + CGAL_DECL_PREDICATE(Less_or_equal_lexicographically); + CGAL_DECL_PREDICATE(Equal_points); + CGAL_DECL_PREDICATE(Has_on_positive_side); + CGAL_DECL_PREDICATE_(Orientation); // duplicate with the type + CGAL_DECL_PREDICATE_(Oriented_side); // duplicate with the type + CGAL_DECL_PREDICATE(Orientation_of_points); + CGAL_DECL_PREDICATE(Orientation_of_vectors); + CGAL_DECL_PREDICATE(Side_of_oriented_sphere); + CGAL_DECL_PREDICATE(Side_of_bounded_sphere); + CGAL_DECL_PREDICATE(Side_of_bounded_circumsphere); + CGAL_DECL_PREDICATE(Contained_in_affine_hull); + CGAL_DECL_PREDICATE(In_flat_orientation); + CGAL_DECL_PREDICATE(In_flat_side_of_oriented_sphere); + CGAL_DECL_PREDICATE(Construct_flat_orientation); // Making it a predicate is a questionable choice, it should be possible to let it be a construction for some implementations. Not sure how to do that... TODO + CGAL_DECL_PREDICATE(Linear_rank); + CGAL_DECL_PREDICATE(Affine_rank); + CGAL_DECL_PREDICATE(Linearly_independent); + CGAL_DECL_PREDICATE(Affinely_independent); + CGAL_DECL_PREDICATE(Contained_in_linear_hull); + CGAL_DECL_PREDICATE(Contained_in_simplex); + CGAL_DECL_PREDICATE(Power_side_of_power_sphere_raw); + CGAL_DECL_PREDICATE(Power_side_of_power_sphere); + CGAL_DECL_PREDICATE(In_flat_power_side_of_power_sphere_raw); + CGAL_DECL_PREDICATE(In_flat_power_side_of_power_sphere); +#undef CGAL_DECL_PREDICATE + +#define CGAL_DECL_MISC(X) struct X##_tag {}; \ + templatestruct Get_functor_category{typedef Misc_tag type;} + //TODO: split into _begin and _end ? + //CGAL_DECL_MISC(Construct_point_cartesian_const_iterator); + //CGAL_DECL_MISC(Construct_vector_cartesian_const_iterator); + CGAL_DECL_MISC(Point_dimension); + CGAL_DECL_MISC(Vector_dimension); + CGAL_DECL_MISC(Linear_base); // Find a more appropriate category? +#undef CGAL_DECL_MISC + + + // Properties for LA + struct Has_extra_dimension_tag {}; + struct Has_vector_plus_minus_tag {}; + struct Has_vector_scalar_ops_tag {}; + struct Has_dot_product_tag {}; + struct Has_determinant_of_vectors_tag {}; + struct Has_determinant_of_points_tag {}; + struct Has_determinant_of_iterator_to_vectors_tag {}; + struct Has_determinant_of_iterator_to_points_tag {}; + struct Has_determinant_of_vectors_omit_last_tag {}; + struct Stores_squared_norm_tag {}; + + template struct Preserved_by_non_linear_extra_coordinate + : boost::false_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + : boost::true_type {}; + + // Kernel properties + struct Point_stores_squared_distance_to_origin_tag {}; + +} +#endif // CGAL_FUNCTOR_TAGS_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/static_int.h b/include/gudhi_patches/CGAL/NewKernel_d/static_int.h new file mode 100644 index 00000000..21858804 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/static_int.h @@ -0,0 +1,61 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_STATIC_INT_H +#define CGAL_STATIC_INT_H +#include + +namespace CGAL { +template struct static_zero { + operator NT() const { return constant(); } +}; +template struct static_one { + operator NT() const { return constant(); } +}; + +template static_zero operator-(static_zero) { return static_zero(); } + +template NT operator+(NT const& x, static_zero) { return x; } +template NT operator+(static_zero, NT const& x) { return x; } +template static_zero operator+(static_zero, static_zero) { return static_zero(); } +template static_one operator+(static_zero, static_one) { return static_one(); } +template static_one operator+(static_one, static_zero) { return static_one(); } + +template NT operator-(NT const& x, static_zero) { return x; } +template NT operator-(static_zero, NT const& x) { return -x; } +template static_zero operator-(static_zero, static_zero) { return static_zero(); } +template static_zero operator-(static_one, static_one) { return static_zero(); } +template static_one operator-(static_one, static_zero) { return static_one(); } + +template NT operator*(NT const& x, static_one) { return x; } +template NT operator*(static_one, NT const& x) { return x; } +template static_zero operator*(NT const&, static_zero) { return static_zero(); } +template static_zero operator*(static_zero, NT const&) { return static_zero(); } +template static_zero operator*(static_zero, static_zero) { return static_zero(); } +template static_one operator*(static_one, static_one) { return static_one(); } +template static_zero operator*(static_zero, static_one) { return static_zero(); } +template static_zero operator*(static_one, static_zero) { return static_zero(); } + +template NT operator/(NT const& x, static_one) { return x; } +template static_zero operator/(static_zero, NT const&) { return static_zero(); } +template static_zero operator/(static_zero, static_one) { return static_zero(); } +template static_one operator/(static_one, static_one) { return static_one(); } + +} +#endif // CGAL_STATIC_INT_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h b/include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h new file mode 100644 index 00000000..253e1282 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h @@ -0,0 +1,104 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_STORE_KERNEL_H +#define CGAL_STORE_KERNEL_H + +#include +#include + +namespace CGAL { +namespace internal { +BOOST_MPL_HAS_XXX_TRAIT_DEF(Do_not_store_kernel) +template::value,bool=has_Do_not_store_kernel::value> struct Do_not_store_kernel { + enum { value=false }; + typedef Tag_false type; +}; +template struct Do_not_store_kernel { + enum { value=true }; + typedef Tag_true type; +}; +template struct Do_not_store_kernel { + typedef typename T::Do_not_store_kernel type; + enum { value=type::value }; +}; +} + +template::value> +struct Store_kernel { + Store_kernel(){} + Store_kernel(R_ const&){} + enum { kernel_is_stored = false }; + R_ kernel()const{return R_();} + typedef R_ reference_type; + void set_kernel(R_ const&){} +}; +template +struct Store_kernel { + Store_kernel():rp(0){ + CGAL_warning_msg(true,"I should know my kernel"); + } + Store_kernel(R_ const& r):rp(&r){} + enum { kernel_is_stored = true }; + R_ const& kernel()const{ + CGAL_warning_msg(rp!=0,"I should know my kernel"); + return *rp; + } + typedef R_ const& reference_type; + void set_kernel(R_ const&r){rp=&r;} + private: + R_ const* rp; +}; + +//For a second kernel. TODO: find something more elegant +template::value> +struct Store_kernel2 { + Store_kernel2(){} + Store_kernel2(R_ const&){} + enum { kernel2_is_stored = false }; + R_ kernel2()const{return R_();} + typedef R_ reference2_type; + void set_kernel2(R_ const&){} +}; +template +struct Store_kernel2 { + Store_kernel2(){ + //CGAL_warning_msg(true,"I should know my kernel"); + } + Store_kernel2(R_ const& r):rp(&r){} + enum { kernel2_is_stored = true }; + R_ const& kernel2()const{ + CGAL_warning_msg(rp==0,"I should know my kernel"); + return *rp; + } + typedef R_ const& reference2_type; + void set_kernel2(R_ const&r){rp=&r;} + private: + R_ const* rp; +}; +} +#define CGAL_BASE_INIT(X,Y) \ + X():Y(){} \ + X(R_ const&r):Y(r){} +#define CGAL_FUNCTOR_INIT_STORE(X) CGAL_BASE_INIT(X,Store_kernel) +#define CGAL_FUNCTOR_INIT_IGNORE(X) \ + X(){} \ + X(R_ const&){} + +#endif // CGAL_STORE_KERNEL_H diff --git a/include/gudhi_patches/CGAL/NewKernel_d/utils.h b/include/gudhi_patches/CGAL/NewKernel_d/utils.h new file mode 100644 index 00000000..238a2230 --- /dev/null +++ b/include/gudhi_patches/CGAL/NewKernel_d/utils.h @@ -0,0 +1,306 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_MARCUTILS +#define CGAL_MARCUTILS + +#include + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4003) // not enough actual parameters for macro 'BOOST_PP_EXPAND_I' + // http://lists.boost.org/boost-users/2014/11/83291.php +#endif + +#ifdef CGAL_CXX11 +#include +#include +#define CGAL_FORWARDABLE(T) T&& +#define CGAL_FORWARD(T,t) std::forward(t) +#define CGAL_MOVE(t) std::move(t) +#define CGAL_CONSTEXPR constexpr +#else +#define CGAL_FORWARDABLE(T) T const& +#define CGAL_FORWARD(T,t) t +#define CGAL_MOVE(t) t +#define CGAL_CONSTEXPR +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef CGAL_CXX11 +#define CGAL_BOOSTD std:: +#else +#define CGAL_BOOSTD boost:: +#endif + +namespace CGAL { +namespace internal { + BOOST_MPL_HAS_XXX_TRAIT_DEF(type) +} + +template ::value /*false*/> +struct Has_type_different_from : boost::false_type {}; +template +struct Has_type_different_from +: boost::mpl::not_ > {}; + + + template struct Wrap_type { typedef T type; }; + + // tell a function f(a,b,c) that its real argument is a(b,c) + struct Eval_functor {}; + + // forget the first argument. Useful to make something dependant + // (and thus usable in SFINAE), although that's not a great design. + template struct Second_arg { + typedef B type; + }; + + // like std::forward, except for basic types where it does a cast, to + // avoid issues with narrowing conversions +#ifdef CGAL_CXX11 + template inline + typename std::conditional::value&&std::is_arithmetic::type>::value,T,U&&>::type + forward_safe(V&& u) { return std::forward(u); } +#else + template inline U const& forward_safe(U const& u) { + return u; + } +#endif + +#ifdef CGAL_CXX11 + template struct Constructible_from_each; + template struct Constructible_from_each{ + enum { value=std::is_convertible::value&&Constructible_from_each::value }; + }; + template struct Constructible_from_each{ + enum { value=true }; + }; +#else +// currently only used in C++0X code +#endif + + template struct Scale { +#ifndef CGAL_CXX11 + template struct result; + template struct result { + typedef FT type; + }; +#endif + T const& scale; + Scale(T const& t):scale(t){} + template +#ifdef CGAL_CXX11 + auto operator()(FT&& x)const->decltype(scale*std::forward(x)) +#else + FT operator()(FT const& x)const +#endif + { + return scale*CGAL_FORWARD(FT,x); + } + }; + template struct Divide { +#if !defined(CGAL_CXX11) || !defined(BOOST_RESULT_OF_USE_DECLTYPE) + // requires boost > 1.44 + // shouldn't be needed with C++0X + //template struct result; + //template struct result { + // typedef FT type; + //}; + typedef NT result_type; +#endif + T const& scale; + Divide(T const& t):scale(t){} + template +#ifdef CGAL_CXX11 + //FIXME: gcc complains for Gmpq + //auto operator()(FT&& x)const->decltype(Rational_traits().make_rational(std::forward(x),scale)) + NT operator()(FT&& x)const +#else + NT operator()(FT const& x)const +#endif + { + return Rational_traits(). + make_rational(CGAL_FORWARD(FT,x),scale); + } + }; + + template struct has_cheap_constructor : boost::is_arithmetic{}; + template struct has_cheap_constructor > { + enum { value=true }; + }; + + // like std::multiplies but allows mixing types + // in C++11 in doesn't need to be a template + template < class Ret > + struct multiplies { + template +#ifdef CGAL_CXX11 + auto operator()(A&&a,B&&b)const->decltype(std::forward(a)*std::forward(b)) +#else + Ret operator()(A const& a, B const& b)const +#endif + { + return CGAL_FORWARD(A,a)*CGAL_FORWARD(B,b); + } + }; + template < class Ret > + struct division { + template +#ifdef CGAL_CXX11 + auto operator()(A&&a,B&&b)const->decltype(std::forward(a)/std::forward(b)) +#else + Ret operator()(A const& a, B const& b)const +#endif + { + return CGAL_FORWARD(A,a)/CGAL_FORWARD(B,b); + } + }; + +#ifdef CGAL_CXX11 + using std::decay; +#else + template struct decay : boost::remove_cv::type> {}; +#endif + + template struct Type_copy_ref { typedef U type; }; + template struct Type_copy_ref { typedef U& type; }; +#ifdef CGAL_CXX11 + template struct Type_copy_ref { typedef U&& type; }; +#endif + template struct Type_copy_cv { typedef U type; }; + template struct Type_copy_cv { typedef U const type; }; + template struct Type_copy_cv { typedef U volatile type; }; + template struct Type_copy_cv { typedef U const volatile type; }; + + template struct Type_copy_cvref : + Type_copy_ref::type,U>::type> {}; + + struct Dereference_functor { + template struct result{}; + template struct result { + typedef typename std::iterator_traits::reference type; + }; + template typename result::type + operator()(It const&i)const{ + return *i; + } + }; + +#ifdef CGAL_CXX11 + template struct Indices{}; + template struct Next_increasing_indices; + template struct Next_increasing_indices > { + typedef Indices type; + }; + template struct N_increasing_indices { + typedef typename Next_increasing_indices::type>::type type; + }; + template<> struct N_increasing_indices<0> { typedef Indices<> type; }; + namespace internal { + template inline typename std::result_of::type + do_call_on_tuple_elements(F&&f, std::tuple&&t, Indices&&) { + return f(std::get(std::move(t))...); + } + } // internal + template + inline typename std::result_of::type + call_on_tuple_elements(F&&f, std::tuple&&t) { + return internal::do_call_on_tuple_elements(std::forward(f),std::move(t), + typename N_increasing_indices::type()); + } +#else +#define CGAL_VAR(Z,N,_) cpp0x::get(t) +#define CGAL_CODE(Z,N,_) template \ + inline Res call_on_tuple_elements(F const&f, \ + cpp0x::tuple const&t) { \ + return f(BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + template + inline Res call_on_tuple_elements(F const&f, cpp0x::tuple<>) { + return f(); + } +BOOST_PP_REPEAT_FROM_TO(1, 8, CGAL_CODE, _ ) +#undef CGAL_CODE +#undef CGAL_VAR +#endif + + template struct Factory { + typedef A result_type; +#ifdef CGAL_CXX11 + template result_type operator()(U&&...u)const{ + return A(std::forward(u)...); + } +#else + result_type operator()()const{ + return A(); + } +#define CGAL_CODE(Z,N,_) template \ + result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,U,const&u))const{ \ + return A(BOOST_PP_ENUM_PARAMS(N,u)); \ + } +BOOST_PP_REPEAT_FROM_TO(1, 8, CGAL_CODE, _ ) +#undef CGAL_CODE +#endif + }; +} + +// TODO: make a Cartesian-only variant +// WARNING: do not use the Req* parameters too much, they can cause circular instanciations and are only useful for dispatching. +#define CGAL_STRIP_PAREN_(...) __VA_ARGS__ +#define CGAL_STRIP_PAREN(...) CGAL_STRIP_PAREN_ __VA_ARGS__ +// What to do with O? pass it down to other functors or drop it? +#define CGAL_KD_DEFAULT_FUNCTOR(Tg,Name,ReqTyp,ReqFun) \ + template \ + struct Get_functor::value \ + || !Provides_types >::value \ + || !Provides_functors >::value \ + , int, void>::type> \ + { \ + typedef CGAL_STRIP_PAREN_ Name type; \ + typedef K Bound_kernel; \ + } + +// Not used yet, may need some changes. +#define CGAL_KD_DEFAULT_TYPE(Tg,Name,ReqTyp,ReqFun) \ + template \ + struct Get_type::value \ + || !Provides_types >::value \ + || !Provides_functors >::value \ + , int, void>::type> \ + { \ + typedef CGAL_STRIP_PAREN_ Name type; \ + typedef K Bound_kernel; \ + } + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif diff --git a/include/gudhi_patches/CGAL/Orthogonal_incremental_neighbor_search.h b/include/gudhi_patches/CGAL/Orthogonal_incremental_neighbor_search.h new file mode 100644 index 00000000..e29ce14f --- /dev/null +++ b/include/gudhi_patches/CGAL/Orthogonal_incremental_neighbor_search.h @@ -0,0 +1,620 @@ +// Copyright (c) 2002,2011 Utrecht University (The Netherlands). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Hans Tangelder () + +#ifndef CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH +#define CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + + template ::type, + class Splitter_ = Sliding_midpoint, + class Tree_= Kd_tree > + class Orthogonal_incremental_neighbor_search { + + public: + typedef Splitter_ Splitter; + typedef Tree_ Tree; + typedef Distance_ Distance; + typedef typename SearchTraits::Point_d Point_d; + typedef typename Distance::Query_item Query_item; + typedef typename SearchTraits::FT FT; + typedef typename Tree::Point_d_iterator Point_d_iterator; + typedef typename Tree::Node_const_handle Node_const_handle; + + typedef std::pair Point_with_transformed_distance; + typedef CGAL::cpp11::tuple > Node_with_distance; + typedef std::vector Node_with_distance_vector; + typedef std::vector Point_with_transformed_distance_vector; + + template + struct Object_wrapper + { + T object; + Object_wrapper(const T& t):object(t){} + const T& operator* () const { return object; } + const T* operator-> () const { return &object; } + }; + + class Iterator_implementation { + SearchTraits traits; + public: + + int number_of_neighbours_computed; + int number_of_internal_nodes_visited; + int number_of_leaf_nodes_visited; + int number_of_items_visited; + + private: + + typedef std::vector Distance_vector; + + Distance_vector dists; + + Distance Orthogonal_distance_instance; + + FT multiplication_factor; + + Query_item query_point; + + FT distance_to_root; + + bool search_nearest_neighbour; + + FT rd; + + + class Priority_higher { + public: + + bool search_nearest; + + Priority_higher(bool search_the_nearest_neighbour) + : search_nearest(search_the_nearest_neighbour) + {} + + //highest priority is smallest distance + bool + operator() (Node_with_distance* n1, Node_with_distance* n2) const + { + return (search_nearest) ? (CGAL::cpp11::get<1>(*n1) > CGAL::cpp11::get<1>(*n2)) : (CGAL::cpp11::get<1>(*n2) > CGAL::cpp11::get<1>(*n1)); + } + }; + + class Distance_smaller { + + public: + + bool search_nearest; + + Distance_smaller(bool search_the_nearest_neighbour) + : search_nearest(search_the_nearest_neighbour) + {} + + //highest priority is smallest distance + bool operator() (Point_with_transformed_distance* p1, Point_with_transformed_distance* p2) const + { + return (search_nearest) ? (p1->second > p2->second) : (p2->second > p1->second); + } + }; + + + std::priority_queue PriorityQueue; + + public: + std::priority_queue Item_PriorityQueue; + + + public: + + int reference_count; + + + + // constructor + Iterator_implementation(const Tree& tree,const Query_item& q, const Distance& tr, + FT Eps=FT(0.0), bool search_nearest=true) + : traits(tree.traits()),number_of_neighbours_computed(0), number_of_internal_nodes_visited(0), + number_of_leaf_nodes_visited(0), number_of_items_visited(0), + Orthogonal_distance_instance(tr), multiplication_factor(Orthogonal_distance_instance.transformed_distance(FT(1.0)+Eps)), + query_point(q), search_nearest_neighbour(search_nearest), + PriorityQueue(Priority_higher(search_nearest)), Item_PriorityQueue(Distance_smaller(search_nearest)), + reference_count(1) + + + { + if (tree.empty()) return; + + typename SearchTraits::Construct_cartesian_const_iterator_d ccci=traits.construct_cartesian_const_iterator_d_object(); + int dim = static_cast(std::distance(ccci(q), ccci(q,0))); + + dists.resize(dim); + for(int i=0 ; i(*The_Root); + Compute_the_next_nearest_neighbour(); + } + else{ + distance_to_root= + Orthogonal_distance_instance.max_distance_to_rectangle(q, + tree.bounding_box(), dists); + Node_with_distance *The_Root = new Node_with_distance(tree.root(), + distance_to_root, dists); + PriorityQueue.push(The_Root); + + // rd is the distance of the top of the priority queue to q + rd=CGAL::cpp11::get<1>(*The_Root); + Compute_the_next_furthest_neighbour(); + } + + + } + + // * operator + const Point_with_transformed_distance& + operator* () const + { + return *(Item_PriorityQueue.top()); + } + + // prefix operator + Iterator_implementation& + operator++() + { + Delete_the_current_item_top(); + if(search_nearest_neighbour) + Compute_the_next_nearest_neighbour(); + else + Compute_the_next_furthest_neighbour(); + return *this; + } + + // postfix operator + Object_wrapper + operator++(int) + { + Object_wrapper result( *(Item_PriorityQueue.top()) ); + ++*this; + return result; + } + + // Print statistics of the general priority search process. + std::ostream& + statistics (std::ostream& s) const { + s << "Orthogonal priority search statistics:" + << std::endl; + s << "Number of internal nodes visited:" + << number_of_internal_nodes_visited << std::endl; + s << "Number of leaf nodes visited:" + << number_of_leaf_nodes_visited << std::endl; + s << "Number of items visited:" + << number_of_items_visited << std::endl; + s << "Number of neighbours computed:" + << number_of_neighbours_computed << std::endl; + return s; + } + + + //destructor + ~Iterator_implementation() + { + while (!PriorityQueue.empty()) { + Node_with_distance* The_top=PriorityQueue.top(); + PriorityQueue.pop(); + delete The_top; + } + while (!Item_PriorityQueue.empty()) { + Point_with_transformed_distance* The_top=Item_PriorityQueue.top(); + Item_PriorityQueue.pop(); + delete The_top; + } + } + + private: + + void + Delete_the_current_item_top() + { + Point_with_transformed_distance* The_item_top=Item_PriorityQueue.top(); + Item_PriorityQueue.pop(); + delete The_item_top; + } + + void + Compute_the_next_nearest_neighbour() + { + // compute the next item + bool next_neighbour_found=false; + if (!(Item_PriorityQueue.empty())) { + next_neighbour_found= + (multiplication_factor*rd > Item_PriorityQueue.top()->second); + } + typename SearchTraits::Construct_cartesian_const_iterator_d construct_it=traits.construct_cartesian_const_iterator_d_object(); + typename SearchTraits::Cartesian_const_iterator_d query_point_it = construct_it(query_point); + // otherwise browse the tree further + while ((!next_neighbour_found) && (!PriorityQueue.empty())) { + Node_with_distance* The_node_top=PriorityQueue.top(); + Node_const_handle N= CGAL::cpp11::get<0>(*The_node_top); + dists = CGAL::cpp11::get<2>(*The_node_top); + PriorityQueue.pop(); + delete The_node_top; + FT copy_rd=rd; + while (!(N->is_leaf())) { // compute new distance + typename Tree::Internal_node_const_handle node = + static_cast(N); + number_of_internal_nodes_visited++; + int new_cut_dim=node->cutting_dimension(); + FT new_rd,dst = dists[new_cut_dim]; + FT val = *(query_point_it + new_cut_dim); + FT diff1 = val - node->upper_low_value(); + FT diff2 = val - node->lower_high_value(); + if (diff1 + diff2 < FT(0.0)) { + new_rd= + Orthogonal_distance_instance.new_distance(copy_rd,dst,diff1,new_cut_dim); + + CGAL_assertion(new_rd >= copy_rd); + dists[new_cut_dim] = diff1; + Node_with_distance *Upper_Child = + new Node_with_distance(node->upper(), new_rd, dists); + PriorityQueue.push(Upper_Child); + dists[new_cut_dim] = dst; + N=node->lower(); + + } + else { // compute new distance + new_rd=Orthogonal_distance_instance.new_distance(copy_rd,dst,diff2,new_cut_dim); + CGAL_assertion(new_rd >= copy_rd); + dists[new_cut_dim] = diff2; + Node_with_distance *Lower_Child = + new Node_with_distance(node->lower(), new_rd, dists); + PriorityQueue.push(Lower_Child); + dists[new_cut_dim] = dst; + N=node->upper(); + } + } + // n is a leaf + typename Tree::Leaf_node_const_handle node = + static_cast(N); + number_of_leaf_nodes_visited++; + if (node->size() > 0) { + for (typename Tree::iterator it=node->begin(); it != node->end(); it++) { + number_of_items_visited++; + FT distance_to_query_point= + Orthogonal_distance_instance.transformed_distance(query_point,*it); + Point_with_transformed_distance *NN_Candidate= + new Point_with_transformed_distance(*it,distance_to_query_point); + Item_PriorityQueue.push(NN_Candidate); + } + // old top of PriorityQueue has been processed, + // hence update rd + + if (!(PriorityQueue.empty())) { + rd = CGAL::cpp11::get<1>(*PriorityQueue.top()); + next_neighbour_found = + (multiplication_factor*rd > + Item_PriorityQueue.top()->second); + } + else // priority queue empty => last neighbour found + { + next_neighbour_found=true; + } + + number_of_neighbours_computed++; + } + } // next_neighbour_found or priority queue is empty + // in the latter case also the item priority quee is empty + } + + + void + Compute_the_next_furthest_neighbour() + { + // compute the next item + bool next_neighbour_found=false; + if (!(Item_PriorityQueue.empty())) { + next_neighbour_found= + (rd < multiplication_factor*Item_PriorityQueue.top()->second); + } + typename SearchTraits::Construct_cartesian_const_iterator_d construct_it=traits.construct_cartesian_const_iterator_d_object(); + typename SearchTraits::Cartesian_const_iterator_d query_point_it = construct_it(query_point); + // otherwise browse the tree further + while ((!next_neighbour_found) && (!PriorityQueue.empty())) { + Node_with_distance* The_node_top=PriorityQueue.top(); + Node_const_handle N= CGAL::cpp11::get<0>(*The_node_top); + dists = CGAL::cpp11::get<2>(*The_node_top); + PriorityQueue.pop(); + delete The_node_top; + FT copy_rd=rd; + while (!(N->is_leaf())) { // compute new distance + typename Tree::Internal_node_const_handle node = + static_cast(N); + number_of_internal_nodes_visited++; + int new_cut_dim=node->cutting_dimension(); + FT new_rd,dst = dists[new_cut_dim]; + FT val = *(query_point_it + new_cut_dim); + FT diff1 = val - node->upper_low_value(); + FT diff2 = val - node->lower_high_value(); + if (diff1 + diff2 < FT(0.0)) { + diff1 = val - node->upper_high_value(); + new_rd= + Orthogonal_distance_instance.new_distance(copy_rd,dst,diff1,new_cut_dim); + Node_with_distance *Lower_Child = + new Node_with_distance(node->lower(), copy_rd, dists); + PriorityQueue.push(Lower_Child); + N=node->upper(); + dists[new_cut_dim] = diff1; + copy_rd=new_rd; + + } + else { // compute new distance + diff2 = val - node->lower_low_value(); + new_rd=Orthogonal_distance_instance.new_distance(copy_rd,dst,diff2,new_cut_dim); + Node_with_distance *Upper_Child = + new Node_with_distance(node->upper(), copy_rd, dists); + PriorityQueue.push(Upper_Child); + N=node->lower(); + dists[new_cut_dim] = diff2; + copy_rd=new_rd; + } + } + // n is a leaf + typename Tree::Leaf_node_const_handle node = + static_cast(N); + number_of_leaf_nodes_visited++; + if (node->size() > 0) { + for (typename Tree::iterator it=node->begin(); it != node->end(); it++) { + number_of_items_visited++; + FT distance_to_query_point= + Orthogonal_distance_instance.transformed_distance(query_point,*it); + Point_with_transformed_distance *NN_Candidate= + new Point_with_transformed_distance(*it,distance_to_query_point); + Item_PriorityQueue.push(NN_Candidate); + } + // old top of PriorityQueue has been processed, + // hence update rd + + if (!(PriorityQueue.empty())) { + rd = CGAL::cpp11::get<1>(*PriorityQueue.top()); + next_neighbour_found = + (multiplication_factor*rd < + Item_PriorityQueue.top()->second); + } + else // priority queue empty => last neighbour found + { + next_neighbour_found=true; + } + + number_of_neighbours_computed++; + } + } // next_neighbour_found or priority queue is empty + // in the latter case also the item priority quee is empty + } + }; // class Iterator_implementaion + + + + + + + + + + public: + class iterator; + typedef iterator const_iterator; + + // constructor + Orthogonal_incremental_neighbor_search(const Tree& tree, + const Query_item& q, FT Eps = FT(0.0), + bool search_nearest=true, const Distance& tr=Distance()) + : m_tree(tree),m_query(q),m_dist(tr),m_Eps(Eps),m_search_nearest(search_nearest) + {} + + iterator + begin() const + { + return iterator(m_tree,m_query,m_dist,m_Eps,m_search_nearest); + } + + iterator + end() const + { + return iterator(); + } + + std::ostream& + statistics(std::ostream& s) + { + begin()->statistics(s); + return s; + } + + + + + class iterator { + + public: + + typedef std::input_iterator_tag iterator_category; + typedef Point_with_transformed_distance value_type; + typedef Point_with_transformed_distance* pointer; + typedef const Point_with_transformed_distance& reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef int distance_type; + + //class Iterator_implementation; + Iterator_implementation *Ptr_implementation; + + + public: + + // default constructor + iterator() + : Ptr_implementation(0) + {} + + int + the_number_of_items_visited() + { + return Ptr_implementation->number_of_items_visited; + } + + // constructor + iterator(const Tree& tree,const Query_item& q, const Distance& tr=Distance(), FT eps=FT(0.0), + bool search_nearest=true) + : Ptr_implementation(new Iterator_implementation(tree, q, tr, eps, search_nearest)) + {} + + // copy constructor + iterator(const iterator& Iter) + { + Ptr_implementation = Iter.Ptr_implementation; + if (Ptr_implementation != 0) Ptr_implementation->reference_count++; + } + + iterator& operator=(const iterator& Iter) + { + if (Ptr_implementation != Iter.Ptr_implementation){ + if (Ptr_implementation != 0 && --(Ptr_implementation->reference_count)==0) { + delete Ptr_implementation; + } + Ptr_implementation = Iter.Ptr_implementation; + if (Ptr_implementation != 0) Ptr_implementation->reference_count++; + } + return *this; + } + + + const Point_with_transformed_distance& + operator* () const + { + return *(*Ptr_implementation); + } + + // -> operator + const Point_with_transformed_distance* + operator-> () const + { + return &*(*Ptr_implementation); + } + + // prefix operator + iterator& + operator++() + { + ++(*Ptr_implementation); + return *this; + } + + // postfix operator + Object_wrapper + operator++(int) + { + return (*Ptr_implementation)++; + } + + + bool + operator==(const iterator& It) const + { + if ( + ((Ptr_implementation == 0) || + Ptr_implementation->Item_PriorityQueue.empty()) && + ((It.Ptr_implementation == 0) || + It.Ptr_implementation->Item_PriorityQueue.empty()) + ) + return true; + // else + return (Ptr_implementation == It.Ptr_implementation); + } + + bool + operator!=(const iterator& It) const + { + return !(*this == It); + } + + std::ostream& + statistics (std::ostream& s) + { + Ptr_implementation->statistics(s); + return s; + } + + ~iterator() + { + if (Ptr_implementation != 0) { + Ptr_implementation->reference_count--; + if (Ptr_implementation->reference_count==0) { + delete Ptr_implementation; + Ptr_implementation = 0; + } + } + } + + + }; // class iterator + + //data members + const Tree& m_tree; + Query_item m_query; + Distance m_dist; + FT m_Eps; + bool m_search_nearest; + }; // class + + template + void swap (typename Orthogonal_incremental_neighbor_search::iterator& x, + typename Orthogonal_incremental_neighbor_search::iterator& y) + { + typename Orthogonal_incremental_neighbor_search::iterator::Iterator_implementation + *tmp = x.Ptr_implementation; + x.Ptr_implementation = y.Ptr_implementation; + y.Ptr_implementation = tmp; + } + +} // namespace CGAL + +#endif // CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH_H diff --git a/include/gudhi_patches/CGAL/Regular_triangulation.h b/include/gudhi_patches/CGAL/Regular_triangulation.h new file mode 100644 index 00000000..111c6ac9 --- /dev/null +++ b/include/gudhi_patches/CGAL/Regular_triangulation.h @@ -0,0 +1,1169 @@ +// Copyright (c) 2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Clement Jamin + +#ifndef CGAL_REGULAR_TRIANGULATION_H +#define CGAL_REGULAR_TRIANGULATION_H + +#include +#include +#include +#include +#include + +#include + +namespace CGAL { + +template< typename Traits_, typename TDS_ = Default > +class Regular_triangulation +: public Triangulation< + Regular_triangulation_traits_adapter, + typename Default::Get< + TDS_, + Triangulation_data_structure< + typename Regular_triangulation_traits_adapter::Dimension, + Triangulation_vertex >, + Triangulation_full_cell > + > + >::type> +{ + typedef Regular_triangulation_traits_adapter RTTraits; + typedef typename RTTraits::Dimension Maximal_dimension_; + typedef typename Default::Get< + TDS_, + Triangulation_data_structure< + Maximal_dimension_, + Triangulation_vertex, + Triangulation_full_cell + > >::type TDS; + typedef Triangulation Base; + typedef Regular_triangulation Self; + + typedef typename RTTraits::Orientation_d Orientation_d; + typedef typename RTTraits::Power_side_of_power_sphere_d Power_side_of_power_sphere_d; + typedef typename RTTraits::In_flat_power_side_of_power_sphere_d + In_flat_power_side_of_power_sphere_d; + typedef typename RTTraits::Flat_orientation_d Flat_orientation_d; + typedef typename RTTraits::Construct_flat_orientation_d Construct_flat_orientation_d; + +public: // PUBLIC NESTED TYPES + + typedef RTTraits Geom_traits; + typedef typename Base::Triangulation_ds Triangulation_ds; + + typedef typename Base::Vertex Vertex; + typedef typename Base::Full_cell Full_cell; + typedef typename Base::Facet Facet; + typedef typename Base::Face Face; + + typedef Maximal_dimension_ Maximal_dimension; + typedef typename RTTraits::Bare_point_d Bare_point; + typedef typename RTTraits::Weighted_point_d Weighted_point; + + typedef typename Base::Point_const_iterator Point_const_iterator; + typedef typename Base::Vertex_handle Vertex_handle; + typedef typename Base::Vertex_iterator Vertex_iterator; + typedef typename Base::Vertex_const_handle Vertex_const_handle; + typedef typename Base::Vertex_const_iterator Vertex_const_iterator; + + typedef typename Base::Full_cell_handle Full_cell_handle; + typedef typename Base::Full_cell_iterator Full_cell_iterator; + typedef typename Base::Full_cell_const_handle Full_cell_const_handle; + typedef typename Base::Full_cell_const_iterator Full_cell_const_iterator; + typedef typename Base::Finite_full_cell_const_iterator + Finite_full_cell_const_iterator; + + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + + typedef typename Base::Locate_type Locate_type; + + //Tag to distinguish Delaunay from Regular triangulations + typedef Tag_true Weighted_tag; + +protected: // DATA MEMBERS + + +public: + + using typename Base::Rotor; + using Base::maximal_dimension; + using Base::are_incident_full_cells_valid; + using Base::coaffine_orientation_predicate; + using Base::reset_flat_orientation; + using Base::current_dimension; + using Base::geom_traits; + using Base::index_of_covertex; + //using Base::index_of_second_covertex; + using Base::rotate_rotor; + using Base::infinite_vertex; + using Base::insert_in_hole; + using Base::is_infinite; + using Base::locate; + using Base::points_begin; + using Base::set_neighbors; + using Base::new_full_cell; + using Base::number_of_vertices; + using Base::orientation; + using Base::tds; + using Base::reorient_full_cells; + using Base::full_cell; + using Base::full_cells_begin; + using Base::full_cells_end; + using Base::finite_full_cells_begin; + using Base::finite_full_cells_end; + using Base::vertices_begin; + using Base::vertices_end; + +private: + + // Wrapper + struct Power_side_of_power_sphere_for_non_maximal_dim_d + { + boost::optional* fop; + Construct_flat_orientation_d cfo; + In_flat_power_side_of_power_sphere_d ifpt; + + Power_side_of_power_sphere_for_non_maximal_dim_d( + boost::optional& x, + Construct_flat_orientation_d const&y, + In_flat_power_side_of_power_sphere_d const&z) + : fop(&x), cfo(y), ifpt(z) {} + + template + CGAL::Orientation operator()(Iter a, Iter b, const Weighted_point & p)const + { + if(!*fop) + *fop=cfo(a,b); + return ifpt(fop->get(),a,b,p); + } + }; + +public: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - CREATION / CONSTRUCTORS + + Regular_triangulation(int dim, const Geom_traits &k = Geom_traits()) + : Base(dim, k) + { + } + + // With this constructor, + // the user can specify a Flat_orientation_d object to be used for + // orienting simplices of a specific dimension + // (= preset_flat_orientation_.first) + // It it used by the dark triangulations created by DT::remove + Regular_triangulation( + int dim, + const std::pair &preset_flat_orientation, + const Geom_traits &k = Geom_traits()) + : Base(dim, preset_flat_orientation, k) + { + } + + ~Regular_triangulation() {} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ACCESS + + // Not Documented + Power_side_of_power_sphere_for_non_maximal_dim_d power_side_of_power_sphere_for_non_maximal_dim_predicate() const + { + return Power_side_of_power_sphere_for_non_maximal_dim_d ( + flat_orientation_, + geom_traits().construct_flat_orientation_d_object(), + geom_traits().in_flat_power_side_of_power_sphere_d_object() + ); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + + // Warning: these functions are not correct since they do not restore hidden + // vertices + + Full_cell_handle remove(Vertex_handle); + Full_cell_handle remove(const Weighted_point & p, Full_cell_handle hint = Full_cell_handle()) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, hint); + if( Base::ON_VERTEX == lt ) + { + return remove(s->vertex(f.index(0))); + } + return Full_cell_handle(); + } + + template< typename ForwardIterator > + void remove(ForwardIterator start, ForwardIterator end) + { + while( start != end ) + remove(*start++); + } + + // Not documented + void remove_decrease_dimension(Vertex_handle); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERTIONS + + template< typename ForwardIterator > + std::ptrdiff_t insert(ForwardIterator start, ForwardIterator end) + { + size_type n = number_of_vertices(); + typedef std::vector WP_vec; + WP_vec points(start, end); + + spatial_sort(points.begin(), points.end(), geom_traits()); + + Full_cell_handle hint; + for(typename WP_vec::const_iterator p = points.begin(); p != points.end(); ++p ) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle c = locate (*p, lt, f, ft, hint); + Vertex_handle v = insert (*p, lt, f, ft, c); + + hint = v == Vertex_handle() ? c : v->full_cell(); + } + return number_of_vertices() - n; + } + + Vertex_handle insert(const Weighted_point &, + Locate_type, + const Face &, + const Facet &, + Full_cell_handle); + + Vertex_handle insert(const Weighted_point & p, + Full_cell_handle start = Full_cell_handle()) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, start); + return insert(p, lt, f, ft, s); + } + + Vertex_handle insert(const Weighted_point & p, Vertex_handle hint) + { + CGAL_assertion( Vertex_handle() != hint ); + return insert(p, hint->full_cell()); + } + + Vertex_handle insert_outside_affine_hull(const Weighted_point &); + Vertex_handle insert_in_conflicting_cell( + const Weighted_point &, Full_cell_handle, + Vertex_handle only_if_this_vertex_is_in_the_cz = Vertex_handle()); + + Vertex_handle insert_if_in_star(const Weighted_point &, + Vertex_handle, + Locate_type, + const Face &, + const Facet &, + Full_cell_handle); + + Vertex_handle insert_if_in_star( + const Weighted_point & p, Vertex_handle star_center, + Full_cell_handle start = Full_cell_handle()) + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, start); + return insert_if_in_star(p, star_center, lt, f, ft, s); + } + + Vertex_handle insert_if_in_star( + const Weighted_point & p, Vertex_handle star_center, + Vertex_handle hint) + { + CGAL_assertion( Vertex_handle() != hint ); + return insert_if_in_star(p, star_center, hint->full_cell()); + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - GATHERING CONFLICTING SIMPLICES + + bool is_in_conflict(const Weighted_point &, Full_cell_const_handle) const; + + template< class OrientationPredicate > + Oriented_side perturbed_power_side_of_power_sphere(const Weighted_point &, + Full_cell_const_handle, const OrientationPredicate &) const; + + template< typename OutputIterator > + Facet compute_conflict_zone(const Weighted_point &, Full_cell_handle, OutputIterator) const; + + template < typename OrientationPredicate, typename PowerTestPredicate > + class Conflict_predicate + { + const Self & rt_; + const Weighted_point & p_; + OrientationPredicate ori_; + PowerTestPredicate power_side_of_power_sphere_; + int cur_dim_; + public: + Conflict_predicate( + const Self & rt, + const Weighted_point & p, + const OrientationPredicate & ori, + const PowerTestPredicate & power_side_of_power_sphere) + : rt_(rt), p_(p), ori_(ori), power_side_of_power_sphere_(power_side_of_power_sphere), cur_dim_(rt.current_dimension()) {} + + inline + bool operator()(Full_cell_const_handle s) const + { + bool ok; + if( ! rt_.is_infinite(s) ) + { + Oriented_side power_side_of_power_sphere = power_side_of_power_sphere_(rt_.points_begin(s), rt_.points_begin(s) + cur_dim_ + 1, p_); + if( ON_POSITIVE_SIDE == power_side_of_power_sphere ) + ok = true; + else if( ON_NEGATIVE_SIDE == power_side_of_power_sphere ) + ok = false; + else + ok = ON_POSITIVE_SIDE == rt_.perturbed_power_side_of_power_sphere(p_, s, ori_); + } + else + { + typedef typename Full_cell::Vertex_handle_const_iterator VHCI; + typedef Substitute_point_in_vertex_iterator F; + F spivi(rt_.infinite_vertex(), &p_); + + Orientation o = ori_( + boost::make_transform_iterator(s->vertices_begin(), spivi), + boost::make_transform_iterator(s->vertices_begin() + cur_dim_ + 1, + spivi)); + + if( POSITIVE == o ) + ok = true; + else if( o == NEGATIVE ) + ok = false; + else + ok = (*this)(s->neighbor( s->index( rt_.infinite_vertex() ) )); + } + return ok; + } + }; + + template < typename ConflictPredicate > + class Conflict_traversal_predicate + { + const Self & rt_; + const ConflictPredicate & pred_; + public: + Conflict_traversal_predicate(const Self & rt, const ConflictPredicate & pred) + : rt_(rt), pred_(pred) + {} + inline + bool operator()(const Facet & f) const + { + return pred_(rt_.full_cell(f)->neighbor(rt_.index_of_covertex(f))); + } + }; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + + bool is_valid(bool verbose = false, int level = 0) const; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MISC + + std::size_t number_of_hidden_vertices() const + { + return m_hidden_points.size(); + } + +private: + + template + bool + does_cell_range_contain_vertex(InputIterator cz_begin, InputIterator cz_end, + Vertex_handle vh) const + { + // Check all vertices + while(cz_begin != cz_end) + { + Full_cell_handle fch = *cz_begin; + for (int i = 0 ; i <= current_dimension() ; ++i) + { + if (fch->vertex(i) == vh) + return true; + } + ++cz_begin; + } + return false; + } + + template + void + process_conflict_zone(InputIterator cz_begin, InputIterator cz_end, + OutputIterator vertices_out) const + { + // Get all vertices + while(cz_begin != cz_end) + { + Full_cell_handle fch = *cz_begin; + for (int i = 0 ; i <= current_dimension() ; ++i) + { + Vertex_handle vh = fch->vertex(i); + if (vh->full_cell() != Full_cell_handle()) + { + (*vertices_out++) = vh; + vh->set_full_cell(Full_cell_handle()); + } + } + ++cz_begin; + } + } + + + template + void + process_cz_vertices_after_insertion(InputIterator vertices_begin, + InputIterator vertices_end) + { + // Get all vertices + while(vertices_begin != vertices_end) + { + Vertex_handle vh = *vertices_begin; + if (vh->full_cell() == Full_cell_handle()) + { + m_hidden_points.push_back(vh->point()); + tds().delete_vertex(vh); + } + ++vertices_begin; + } + } + +private: + // Some internal types to shorten notation + using typename Base::Coaffine_orientation_d; + using Base::flat_orientation_; + typedef Conflict_predicate + Conflict_pred_in_subspace; + typedef Conflict_predicate + Conflict_pred_in_fullspace; + typedef Conflict_traversal_predicate + Conflict_traversal_pred_in_subspace; + typedef Conflict_traversal_predicate + Conflict_traversal_pred_in_fullspace; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MEMBER VARIABLES + std::vector m_hidden_points; + +}; // class Regular_triangulation + + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +// FUNCTIONS THAT ARE MEMBER METHODS: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + + +// Warning: this function is not correct since it does not restore hidden +// vertices +template< typename Traits, typename TDS > +typename Regular_triangulation::Full_cell_handle +Regular_triangulation +::remove( Vertex_handle v ) +{ + CGAL_precondition( ! is_infinite(v) ); + CGAL_expensive_precondition( is_vertex(v) ); + + // THE CASE cur_dim == 0 + if( 0 == current_dimension() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + else if( 1 == current_dimension() ) + { // THE CASE cur_dim == 1 + if( 2 == number_of_vertices() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + Full_cell_handle left = v->full_cell(); + if( 0 == left->index(v) ) + left = left->neighbor(1); + CGAL_assertion( 1 == left->index(v) ); + Full_cell_handle right = left->neighbor(0); + tds().associate_vertex_with_full_cell(left, 1, right->vertex(1)); + set_neighbors(left, 0, right->neighbor(0), right->mirror_index(0)); + tds().delete_vertex(v); + tds().delete_full_cell(right); + return left; + } + + // THE CASE cur_dim >= 2 + // Gather the finite vertices sharing an edge with |v| + typedef typename Base::template Full_cell_set Simplices; + Simplices simps; + std::back_insert_iterator out(simps); + tds().incident_full_cells(v, out); + typedef std::set Vertex_set; + Vertex_set verts; + Vertex_handle vh; + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + for( int i = 0; i <= current_dimension(); ++i ) + { + vh = (*it)->vertex(i); + if( is_infinite(vh) ) + continue; + if( vh == v ) + continue; + verts.insert(vh); + } + + // After gathering finite neighboring vertices, create their Dark Delaunay triangulation + typedef Triangulation_vertex Dark_vertex_base; + typedef Triangulation_full_cell< + Geom_traits, + internal::Triangulation::Dark_full_cell_data > Dark_full_cell_base; + typedef Triangulation_data_structure Dark_tds; + typedef Regular_triangulation Dark_triangulation; + typedef typename Dark_triangulation::Face Dark_face; + typedef typename Dark_triangulation::Facet Dark_facet; + typedef typename Dark_triangulation::Vertex_handle Dark_v_handle; + typedef typename Dark_triangulation::Full_cell_handle Dark_s_handle; + + // If flat_orientation_ is defined, we give it the Dark triangulation + // so that the orientation it uses for "current_dimension()"-simplices is + // coherent with the global triangulation + Dark_triangulation dark_side( + maximal_dimension(), + flat_orientation_ ? + std::pair(current_dimension(), flat_orientation_.get_ptr()) + : std::pair(std::numeric_limits::max(), NULL) ); + + Dark_s_handle dark_s; + Dark_v_handle dark_v; + typedef std::map Vertex_map; + Vertex_map light_to_dark; + typename Vertex_set::iterator vit = verts.begin(); + while( vit != verts.end() ) + { + dark_v = dark_side.insert((*vit)->point(), dark_s); + dark_s = dark_v->full_cell(); + dark_v->data() = *vit; + light_to_dark[*vit] = dark_v; + ++vit; + } + + if( dark_side.current_dimension() != current_dimension() ) + { + CGAL_assertion( dark_side.current_dimension() + 1 == current_dimension() ); + // Here, the finite neighbors of |v| span a affine subspace of + // dimension one less than the current dimension. Two cases are possible: + if( (size_type)(verts.size() + 1) == number_of_vertices() ) + { + remove_decrease_dimension(v); + return Full_cell_handle(); + } + else + { // |v| is strictly outside the convex hull of the rest of the points. This is an + // easy case: first, modify the finite full_cells, then, delete the infinite ones. + // We don't even need the Dark triangulation. + Simplices infinite_simps; + { + Simplices finite_simps; + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + if( is_infinite(*it) ) + infinite_simps.push_back(*it); + else + finite_simps.push_back(*it); + simps.swap(finite_simps); + } // now, simps only contains finite simplices + // First, modify the finite full_cells: + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + { + int v_idx = (*it)->index(v); + tds().associate_vertex_with_full_cell(*it, v_idx, infinite_vertex()); + } + // Make the handles to infinite full cells searchable + infinite_simps.make_searchable(); + // Then, modify the neighboring relation + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + { + for( int i = 0 ; i <= current_dimension(); ++i ) + { + if (is_infinite((*it)->vertex(i))) + continue; + (*it)->vertex(i)->set_full_cell(*it); + Full_cell_handle n = (*it)->neighbor(i); + // Was |n| a finite full cell prior to removing |v| ? + if( ! infinite_simps.contains(n) ) + continue; + int n_idx = n->index(v); + set_neighbors(*it, i, n->neighbor(n_idx), n->neighbor(n_idx)->index(n)); + } + } + Full_cell_handle ret_s; + // Then, we delete the infinite full_cells + for( typename Simplices::iterator it = infinite_simps.begin(); it != infinite_simps.end(); ++it ) + tds().delete_full_cell(*it); + tds().delete_vertex(v); + return simps.front(); + } + } + else // From here on, dark_side.current_dimension() == current_dimension() + { + dark_side.infinite_vertex()->data() = infinite_vertex(); + light_to_dark[infinite_vertex()] = dark_side.infinite_vertex(); + } + + // Now, compute the conflict zone of v->point() in + // the dark side. This is precisely the set of full_cells + // that we have to glue back into the light side. + Dark_face dark_f(dark_side.maximal_dimension()); + Dark_facet dark_ft; + typename Dark_triangulation::Locate_type lt; + dark_s = dark_side.locate(v->point(), lt, dark_f, dark_ft); + CGAL_assertion( lt != Dark_triangulation::ON_VERTEX + && lt != Dark_triangulation::OUTSIDE_AFFINE_HULL ); + + // |ret_s| is the full_cell that we return + Dark_s_handle dark_ret_s = dark_s; + Full_cell_handle ret_s; + + typedef typename Base::template Full_cell_set Dark_full_cells; + Dark_full_cells conflict_zone; + std::back_insert_iterator dark_out(conflict_zone); + + dark_ft = dark_side.compute_conflict_zone(v->point(), dark_s, dark_out); + // Make the dark simplices in the conflict zone searchable + conflict_zone.make_searchable(); + + // THE FOLLOWING SHOULD MAYBE GO IN TDS. + // Here is the plan: + // 1. Pick any Facet from boundary of the light zone + // 2. Find corresponding Facet on boundary of dark zone + // 3. stitch. + + // 1. Build a facet on the boudary of the light zone: + Full_cell_handle light_s = *simps.begin(); + Facet light_ft(light_s, light_s->index(v)); + + // 2. Find corresponding Dark_facet on boundary of the dark zone + Dark_full_cells dark_incident_s; + for( int i = 0; i <= current_dimension(); ++i ) + { + if( index_of_covertex(light_ft) == i ) + continue; + Dark_v_handle dark_v = light_to_dark[full_cell(light_ft)->vertex(i)]; + dark_incident_s.clear(); + dark_out = std::back_inserter(dark_incident_s); + dark_side.tds().incident_full_cells(dark_v, dark_out); + for(typename Dark_full_cells::iterator it = dark_incident_s.begin(); + it != dark_incident_s.end(); + ++it) + { + (*it)->data().count_ += 1; + } + } + + for( typename Dark_full_cells::iterator it = dark_incident_s.begin(); it != dark_incident_s.end(); ++it ) + { + if( current_dimension() != (*it)->data().count_ ) + continue; + if( ! conflict_zone.contains(*it) ) + continue; + // We found a full_cell incident to the dark facet corresponding to the light facet |light_ft| + int ft_idx = 0; + while( light_s->has_vertex( (*it)->vertex(ft_idx)->data() ) ) + ++ft_idx; + dark_ft = Dark_facet(*it, ft_idx); + break; + } + // Pre-3. Now, we are ready to traverse both boundary and do the stiching. + + // But first, we create the new full_cells in the light triangulation, + // with as much adjacency information as possible. + + // Create new full_cells with vertices + for( typename Dark_full_cells::iterator it = conflict_zone.begin(); it != conflict_zone.end(); ++it ) + { + Full_cell_handle new_s = new_full_cell(); + (*it)->data().light_copy_ = new_s; + for( int i = 0; i <= current_dimension(); ++i ) + tds().associate_vertex_with_full_cell(new_s, i, (*it)->vertex(i)->data()); + if( dark_ret_s == *it ) + ret_s = new_s; + } + + // Setup adjacencies inside the hole + for( typename Dark_full_cells::iterator it = conflict_zone.begin(); it != conflict_zone.end(); ++it ) + { + Full_cell_handle new_s = (*it)->data().light_copy_; + for( int i = 0; i <= current_dimension(); ++i ) + if( conflict_zone.contains((*it)->neighbor(i)) ) + tds().set_neighbors(new_s, i, (*it)->neighbor(i)->data().light_copy_, (*it)->mirror_index(i)); + } + + // 3. Stitch + simps.make_searchable(); + typedef std::queue > Queue; + Queue q; + q.push(std::make_pair(light_ft, dark_ft)); + dark_s = dark_side.full_cell(dark_ft); + int dark_i = dark_side.index_of_covertex(dark_ft); + // mark dark_ft as visited: + // TODO try by marking with Dark_v_handle (vertex) + dark_s->neighbor(dark_i)->set_neighbor(dark_s->mirror_index(dark_i), Dark_s_handle()); + while( ! q.empty() ) + { + std::pair p = q.front(); + q.pop(); + light_ft = p.first; + dark_ft = p.second; + light_s = full_cell(light_ft); + int light_i = index_of_covertex(light_ft); + dark_s = dark_side.full_cell(dark_ft); + int dark_i = dark_side.index_of_covertex(dark_ft); + Full_cell_handle light_n = light_s->neighbor(light_i); + set_neighbors(dark_s->data().light_copy_, dark_i, light_n, light_s->mirror_index(light_i)); + for( int di = 0; di <= current_dimension(); ++di ) + { + if( di == dark_i ) + continue; + int li = light_s->index(dark_s->vertex(di)->data()); + Rotor light_r(light_s, li, light_i); + typename Dark_triangulation::Rotor dark_r(dark_s, di, dark_i); + + while( simps.contains(cpp11::get<0>(light_r)->neighbor(cpp11::get<1>(light_r))) ) + light_r = rotate_rotor(light_r); + + while( conflict_zone.contains(cpp11::get<0>(dark_r)->neighbor(cpp11::get<1>(dark_r))) ) + dark_r = dark_side.rotate_rotor(dark_r); + + Dark_s_handle dark_ns = cpp11::get<0>(dark_r); + int dark_ni = cpp11::get<1>(dark_r); + Full_cell_handle light_ns = cpp11::get<0>(light_r); + int light_ni = cpp11::get<1>(light_r); + // mark dark_r as visited: + // TODO try by marking with Dark_v_handle (vertex) + Dark_s_handle outside = dark_ns->neighbor(dark_ni); + Dark_v_handle mirror = dark_ns->mirror_vertex(dark_ni, current_dimension()); + int dn = outside->index(mirror); + if( Dark_s_handle() == outside->neighbor(dn) ) + continue; + outside->set_neighbor(dn, Dark_s_handle()); + q.push(std::make_pair(Facet(light_ns, light_ni), Dark_facet(dark_ns, dark_ni))); + } + } + tds().delete_full_cells(simps.begin(), simps.end()); + tds().delete_vertex(v); + return ret_s; +} + +template< typename Traits, typename TDS > +void +Regular_triangulation +::remove_decrease_dimension(Vertex_handle v) +{ + CGAL_precondition( current_dimension() >= 0 ); + tds().remove_decrease_dimension(v, infinite_vertex()); + // reset the predicates: + reset_flat_orientation(); + if( 1 <= current_dimension() ) + { + Full_cell_handle inf_v_cell = infinite_vertex()->full_cell(); + int inf_v_index = inf_v_cell->index(infinite_vertex()); + Full_cell_handle s = inf_v_cell->neighbor(inf_v_index); + Orientation o = orientation(s); + CGAL_assertion( ZERO != o ); + if( NEGATIVE == o ) + reorient_full_cells(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERTIONS + +template< typename Traits, typename TDS > +typename Regular_triangulation::Vertex_handle +Regular_triangulation +::insert(const Weighted_point & p, Locate_type lt, const Face & f, const Facet & ft, Full_cell_handle s) +{ + switch( lt ) + { + case Base::OUTSIDE_AFFINE_HULL: + return insert_outside_affine_hull(p); + break; + case Base::ON_VERTEX: + { + Vertex_handle v = s->vertex(f.index(0)); + typename RTTraits::Compute_weight_d pw = + geom_traits().compute_weight_d_object(); + + if (pw(p) == pw(v->point())) + return v; + // If dim == 0 and the new point has a bigger weight, + // we just replace the point, and the former point gets hidden + else if (current_dimension() == 0) + { + if (pw(p) > pw(v->point())) + { + m_hidden_points.push_back(v->point()); + v->set_point(p); + return v; + } + // Otherwise, the new point is hidden + else + { + m_hidden_points.push_back(p); + return Vertex_handle(); + } + } + // Otherwise, we apply the "normal" algorithm + + // !NO break here! + } + default: + return insert_in_conflicting_cell(p, s); + } +} + +/* +Inserts the point `p` in the regular triangulation. Returns a handle to the +newly created vertex at that position. +\pre The point `p` +must lie outside the affine hull of the regular triangulation. This implies that +`rt`.`current_dimension()` must be smaller than `rt`.`maximal_dimension()`. +*/ +template< typename Traits, typename TDS > +typename Regular_triangulation::Vertex_handle +Regular_triangulation +::insert_outside_affine_hull(const Weighted_point & p) +{ + // we don't use Base::insert_outside_affine_hull(...) because here, we + // also need to reset the side_of_oriented_subsphere functor. + CGAL_precondition( current_dimension() < maximal_dimension() ); + Vertex_handle v = tds().insert_increase_dimension(infinite_vertex()); + // reset the predicates: + reset_flat_orientation(); + v->set_point(p); + if( current_dimension() >= 1 ) + { + Full_cell_handle inf_v_cell = infinite_vertex()->full_cell(); + int inf_v_index = inf_v_cell->index(infinite_vertex()); + Full_cell_handle s = inf_v_cell->neighbor(inf_v_index); + Orientation o = orientation(s); + CGAL_assertion( ZERO != o ); + if( NEGATIVE == o ) + reorient_full_cells(); + + // We just inserted the second finite point and the right infinite + // cell is like : (inf_v, v), but we want it to be (v, inf_v) to be + // consistent with the rest of the cells + if (current_dimension() == 1) + { + // Is "inf_v_cell" the right infinite cell? Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices(current_dimension() - 1, current_dimension()); + } + else + { + inf_v_cell = inf_v_cell->neighbor((inf_v_index + 1) % 2); + inf_v_index = inf_v_cell->index(infinite_vertex()); + // Is "inf_v_cell" the right infinite cell? Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices(current_dimension() - 1, current_dimension()); + } + } + } + } + return v; +} + +template< typename Traits, typename TDS > +typename Regular_triangulation::Vertex_handle +Regular_triangulation +::insert_if_in_star(const Weighted_point & p, + Vertex_handle star_center, + Locate_type lt, + const Face & f, + const Facet & ft, + Full_cell_handle s) +{ + switch( lt ) + { + case Base::OUTSIDE_AFFINE_HULL: + return insert_outside_affine_hull(p); + break; + case Base::ON_VERTEX: + { + Vertex_handle v = s->vertex(f.index(0)); + typename RTTraits::Compute_weight_d pw = + geom_traits().compute_weight_d_object(); + if (pw(p) == pw(v->point())) + return v; + // If dim == 0 and the new point has a bigger weight, + // we replace the point + else if (current_dimension() == 0) + { + if (pw(p) > pw(v->point())) + v->set_point(p); + else + return v; + } + // Otherwise, we apply the "normal" algorithm + + // !NO break here! + } + default: + return insert_in_conflicting_cell(p, s, star_center); + } + + return Vertex_handle(); +} + +/* +[Undocumented function] + +Inserts the point `p` in the regular triangulation. `p` must be +in conflict with the second parameter `c`, which is used as a +starting point for `compute_conflict_zone`. +The function is faster than the standard `insert` function since +it does not need to call `locate`. + +If this insertion creates a vertex, this vertex is returned. + +If `p` coincides with an existing vertex and has a greater weight, +then the existing weighted point becomes hidden and `p` replaces it as vertex +of the triangulation. + +If `p` coincides with an already existing vertex (both point and +weights being equal), then this vertex is returned and the triangulation +remains unchanged. + +Otherwise if `p` does not appear as a vertex of the triangulation, +then it is stored as a hidden point and this method returns the default +constructed handle. + +\pre The point `p` must be in conflict with the full cell `c`. +*/ + +template< typename Traits, typename TDS > +typename Regular_triangulation::Vertex_handle +Regular_triangulation +::insert_in_conflicting_cell(const Weighted_point & p, + Full_cell_handle s, + Vertex_handle only_if_this_vertex_is_in_the_cz) +{ + typedef std::vector Full_cell_h_vector; + + bool in_conflict = is_in_conflict(p, s); + + // If p is not in conflict with s, then p is hidden + // => we don't insert it + if (!in_conflict) + { + m_hidden_points.push_back(p); + return Vertex_handle(); + } + else + { + Full_cell_h_vector cs; // for storing conflicting full_cells. + cs.reserve(64); + std::back_insert_iterator out(cs); + Facet ft = compute_conflict_zone(p, s, out); + + // Check if the CZ contains "only_if_this_vertex_is_in_the_cz" + if (only_if_this_vertex_is_in_the_cz != Vertex_handle() + && !does_cell_range_contain_vertex(cs.begin(), cs.end(), + only_if_this_vertex_is_in_the_cz)) + { + return Vertex_handle(); + } + + // Otherwise, proceed with the insertion + std::vector cz_vertices; + cz_vertices.reserve(64); + process_conflict_zone(cs.begin(), cs.end(), + std::back_inserter(cz_vertices)); + + Vertex_handle ret = insert_in_hole(p, cs.begin(), cs.end(), ft); + + process_cz_vertices_after_insertion(cz_vertices.begin(), cz_vertices.end()); + + return ret; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GATHERING CONFLICTING SIMPLICES + +// NOT DOCUMENTED +template< typename Traits, typename TDS > +template< typename OrientationPred > +Oriented_side +Regular_triangulation +::perturbed_power_side_of_power_sphere(const Weighted_point & p, Full_cell_const_handle s, + const OrientationPred & ori) const +{ + CGAL_precondition_msg( ! is_infinite(s), "full cell must be finite"); + CGAL_expensive_precondition( POSITIVE == orientation(s) ); + typedef std::vector Points; + Points points(current_dimension() + 2); + int i(0); + for( ; i <= current_dimension(); ++i ) + points[i] = &(s->vertex(i)->point()); + points[i] = &p; + std::sort(points.begin(), points.end(), + internal::Triangulation::Compare_points_for_perturbation(*this)); + typename Points::const_reverse_iterator cut_pt = points.rbegin(); + Points test_points; + while( cut_pt != points.rend() ) + { + if( &p == *cut_pt ) + // because the full_cell "s" is assumed to be positively oriented + return ON_NEGATIVE_SIDE; // we consider |p| to lie outside the sphere + test_points.clear(); + Point_const_iterator spit = points_begin(s); + int adjust_sign = -1; + for( i = 0; i < current_dimension(); ++i ) + { + if( &(*spit) == *cut_pt ) + { + ++spit; + adjust_sign = (((current_dimension() + i) % 2) == 0) ? -1 : +1; + } + test_points.push_back(&(*spit)); + ++spit; + } + test_points.push_back(&p); + + typedef typename CGAL::Iterator_project< + typename Points::iterator, + internal::Triangulation::Point_from_pointer, + const Weighted_point &, const Weighted_point * + > Point_pointer_iterator; + + Orientation ori_value = ori( + Point_pointer_iterator(test_points.begin()), + Point_pointer_iterator(test_points.end())); + + if( ZERO != ori_value ) + return Oriented_side( - adjust_sign * ori_value ); + + ++cut_pt; + } + CGAL_assertion(false); // we should never reach here + return ON_NEGATIVE_SIDE; +} + +template< typename Traits, typename TDS > +bool +Regular_triangulation +::is_in_conflict(const Weighted_point & p, Full_cell_const_handle s) const +{ + CGAL_precondition( 1 <= current_dimension() ); + if( current_dimension() < maximal_dimension() ) + { + Conflict_pred_in_subspace c( + *this, p, + coaffine_orientation_predicate(), + power_side_of_power_sphere_for_non_maximal_dim_predicate()); + return c(s); + } + else + { + Orientation_d ori = geom_traits().orientation_d_object(); + Power_side_of_power_sphere_d side = geom_traits().power_side_of_power_sphere_d_object(); + Conflict_pred_in_fullspace c(*this, p, ori, side); + return c(s); + } +} + +template< typename Traits, typename TDS > +template< typename OutputIterator > +typename Regular_triangulation::Facet +Regular_triangulation +::compute_conflict_zone(const Weighted_point & p, Full_cell_handle s, OutputIterator out) const +{ + CGAL_precondition( 1 <= current_dimension() ); + if( current_dimension() < maximal_dimension() ) + { + Conflict_pred_in_subspace c( + *this, p, + coaffine_orientation_predicate(), + power_side_of_power_sphere_for_non_maximal_dim_predicate()); + Conflict_traversal_pred_in_subspace tp(*this, c); + return tds().gather_full_cells(s, tp, out); + } + else + { + Orientation_d ori = geom_traits().orientation_d_object(); + Power_side_of_power_sphere_d side = geom_traits().power_side_of_power_sphere_d_object(); + Conflict_pred_in_fullspace c(*this, p, ori, side); + Conflict_traversal_pred_in_fullspace tp(*this, c); + return tds().gather_full_cells(s, tp, out); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + +template< typename Traits, typename TDS > +bool +Regular_triangulation +::is_valid(bool verbose, int level) const +{ + if (!Base::is_valid(verbose, level)) + return false; + + int dim = current_dimension(); + if (dim == maximal_dimension()) + { + for (Finite_full_cell_const_iterator cit = finite_full_cells_begin() ; + cit != finite_full_cells_end() ; ++cit ) + { + Full_cell_const_handle ch = cit.base(); + for(int i = 0; i < dim+1 ; ++i ) + { + // If the i-th neighbor is not an infinite cell + Vertex_handle opposite_vh = + ch->neighbor(i)->vertex(ch->neighbor(i)->index(ch)); + if (!is_infinite(opposite_vh)) + { + Power_side_of_power_sphere_d side = + geom_traits().power_side_of_power_sphere_d_object(); + if (side(Point_const_iterator(ch->vertices_begin()), + Point_const_iterator(ch->vertices_end()), + opposite_vh->point()) == ON_POSITIVE_SIDE) + { + if (verbose) + CGAL_warning_msg(false, "Non-empty sphere"); + return false; + } + } + } + } + } + return true; +} + +} //namespace CGAL + +#endif //CGAL_REGULAR_TRIANGULATION_H diff --git a/include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h b/include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h new file mode 100644 index 00000000..78bb95a6 --- /dev/null +++ b/include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h @@ -0,0 +1,288 @@ +// Copyright (c) 2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Clement Jamin + +#ifndef CGAL_REGULAR_TRIANGULATION_TRAITS_ADAPTER_H +#define CGAL_REGULAR_TRIANGULATION_TRAITS_ADAPTER_H + +#include + +#include + +namespace CGAL { + +// Wrapper class to make a model of `RegularTriangulationTraits` easily usable +// by the `Regular_triangulation` class. By using this class: +// - Point_d (used by `Triangulation` and the TDS) becomes a weighted point +// - Predicates and functors such as Less_coordinate_d or Orientation_d +// can be called using weighted points instead of bare points (this is +// needed because `Weighted_point_d` is not convertible to `Point_d`) +// This way, `Triangulation` works perfectly well with weighted points. + +template +class Regular_triangulation_traits_adapter + : public K +{ +public: + typedef K Base; + + // Required by TriangulationTraits + typedef typename K::Dimension Dimension; + typedef typename K::FT FT; + typedef typename K::Flat_orientation_d Flat_orientation_d; + typedef typename K::Weighted_point_d Point_d; + + // Required by RegularTriangulationTraits + typedef typename K::Point_d Bare_point_d; + typedef typename K::Weighted_point_d Weighted_point_d; + typedef typename K::Construct_point_d Construct_point_d; + typedef typename K::Compute_weight_d Compute_weight_d; + typedef typename K::Power_side_of_power_sphere_d Power_side_of_power_sphere_d; + typedef typename K::In_flat_power_side_of_power_sphere_d + In_flat_power_side_of_power_sphere_d; + + //=========================================================================== + // Custom types + //=========================================================================== + + // Required by SpatialSortingTraits_d + class Less_coordinate_d + { + const K &m_kernel; + + public: + typedef bool result_type; + + Less_coordinate_d(const K &kernel) + : m_kernel(kernel) {} + + result_type operator()( + Weighted_point_d const& p, Weighted_point_d const& q, int i) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.less_coordinate_d_object() (cp(p), cp(q), i); + } + }; + + //=========================================================================== + + // Required by TriangulationTraits + class Orientation_d + { + const K &m_kernel; + + public: + typedef Orientation result_type; + + Orientation_d(const K &kernel) + : m_kernel(kernel) {} + + template + result_type operator()(ForwardIterator start, ForwardIterator end) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.orientation_d_object() ( + boost::make_transform_iterator(start, cp), + boost::make_transform_iterator(end, cp) + ); + } + }; + + //=========================================================================== + + // Required by TriangulationTraits + class Construct_flat_orientation_d + { + const K &m_kernel; + + public: + typedef Flat_orientation_d result_type; + + Construct_flat_orientation_d(const K &kernel) + : m_kernel(kernel) {} + + template + result_type operator()(ForwardIterator start, ForwardIterator end) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.construct_flat_orientation_d_object() ( + boost::make_transform_iterator(start, cp), + boost::make_transform_iterator(end, cp) + ); + } + }; + + + //=========================================================================== + + // Required by TriangulationTraits + class In_flat_orientation_d + { + const K &m_kernel; + + public: + typedef Orientation result_type; + + In_flat_orientation_d(const K &kernel) + : m_kernel(kernel) {} + + template + result_type operator()(Flat_orientation_d orient, + ForwardIterator start, ForwardIterator end) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.in_flat_orientation_d_object() ( + orient, + boost::make_transform_iterator(start, cp), + boost::make_transform_iterator(end, cp) + ); + } + }; + + //=========================================================================== + + // Required by TriangulationTraits + class Contained_in_affine_hull_d + { + const K &m_kernel; + + public: + typedef bool result_type; + + Contained_in_affine_hull_d(const K &kernel) + : m_kernel(kernel) {} + + template + result_type operator()(ForwardIterator start, ForwardIterator end, + const Weighted_point_d & p) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.contained_in_affine_hull_d_object() ( + boost::make_transform_iterator(start, cp), + boost::make_transform_iterator(end, cp), + cp(p) + ); + } + }; + + //=========================================================================== + + // Required by TriangulationTraits + class Compare_lexicographically_d + { + const K &m_kernel; + + public: + typedef Comparison_result result_type; + + Compare_lexicographically_d(const K &kernel) + : m_kernel(kernel) {} + + result_type operator()( + const Weighted_point_d & p, const Weighted_point_d & q) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.compare_lexicographically_d_object()(cp(p), cp(q)); + } + }; + + //=========================================================================== + + // Only for Triangulation_off_ostream.h (undocumented) + class Compute_coordinate_d + { + const K &m_kernel; + + public: + typedef FT result_type; + + Compute_coordinate_d(const K &kernel) + : m_kernel(kernel) {} + + result_type operator()( + const Weighted_point_d & p, const int i) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.compute_coordinate_d_object()(cp(p), i); + } + }; + + //=========================================================================== + + // To satisfy SpatialSortingTraits_d + // and also for Triangulation_off_ostream.h (undocumented) + class Point_dimension_d + { + const K &m_kernel; + + public: + typedef int result_type; + + Point_dimension_d(const K &kernel) + : m_kernel(kernel) {} + + result_type operator()( + const Weighted_point_d & p) const + { + Construct_point_d cp = m_kernel.construct_point_d_object(); + return m_kernel.point_dimension_d_object()(cp(p)); + } + }; + + //=========================================================================== + // Object creation + //=========================================================================== + + Less_coordinate_d less_coordinate_d_object() const + { + return Less_coordinate_d(*this); + } + Contained_in_affine_hull_d contained_in_affine_hull_d_object() const + { + return Contained_in_affine_hull_d(*this); + } + Orientation_d orientation_d_object() const + { + return Orientation_d(*this); + } + Construct_flat_orientation_d construct_flat_orientation_d_object() const + { + return Construct_flat_orientation_d(*this); + } + In_flat_orientation_d in_flat_orientation_d_object() const + { + return In_flat_orientation_d(*this); + } + Compare_lexicographically_d compare_lexicographically_d_object() const + { + return Compare_lexicographically_d(*this); + } + Compute_coordinate_d compute_coordinate_d_object() const + { + return Compute_coordinate_d(*this); + } + Point_dimension_d point_dimension_d_object() const + { + return Point_dimension_d(*this); + } +}; + + +} //namespace CGAL + +#endif // CGAL_REGULAR_TRIANGULATION_TRAITS_ADAPTER_H diff --git a/include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h b/include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h new file mode 100644 index 00000000..9a6030e5 --- /dev/null +++ b/include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h @@ -0,0 +1,99 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TDS_FULL_CELL_DEFAULT_STORAGE_POLICY_H +#define CGAL_TDS_FULL_CELL_DEFAULT_STORAGE_POLICY_H + +#include +#include +#include + +#include + +namespace CGAL { + +// POLICY TAG + +struct TDS_full_cell_default_storage_policy {}; // stores no additional data. Uses XOR trick. + +template< typename V, typename S, typename D, typename StoragePolicy > +struct TFC_data; // TFC = Triangulation Full Cell + +template< typename Vertex_handle, typename Full_cell_handle, typename Dimen > +struct TFC_data< Vertex_handle, Full_cell_handle, Dimen, TDS_full_cell_default_storage_policy > +{ + typedef typename internal::Dimen_plus_one::type Dimen_plus; + typedef typename internal::S_or_D_array< Vertex_handle, Dimen_plus, true > Vertex_handle_array; + typedef typename internal::S_or_D_array< Full_cell_handle, Dimen_plus > Full_cell_handle_array; + + Vertex_handle_array vertices_; + Full_cell_handle_array neighbors_; + + TFC_data(const int dmax) + : vertices_(dmax+1), neighbors_(dmax+1) + {} + void* for_compact_container() const { return vertices_.for_compact_container(); } + void* & for_compact_container() { return vertices_.for_compact_container(); } + int dimension() const { return ( vertices_.size() - 1 ); } + void set_mirror_index(const int, const int) {} +#ifdef BOOST_NO_INT64_T + typedef std::ptrdiff_t Xor_type; +#else + typedef boost::int_least64_t Xor_type; +#endif + Xor_type xor_of_vertices(const int cur_dim) const + { + Xor_type result(0); + for( int i = 0; i <= cur_dim; ++i ) + result ^= reinterpret_cast(&(*vertices_[i])); + return result; + } + // ASSUMES |*this| is indeed a neighbor of neighbor(i): + // NOT correct when the hole (in insert_in_hole) is doubly covered. + int mirror_index(const int i) const + { + int index = 0; + Full_cell_handle n = neighbors_[i]; + Full_cell_handle o = n->neighbor(index); + while( &(o->combinatorics_) != this ) + o = n->neighbor(++index); + return index; + } + Vertex_handle mirror_vertex(const int i, const int cur_dim) const + { + Xor_type opp_vertex = xor_of_vertices(cur_dim) + ^ neighbors_[i]->xor_of_vertices(cur_dim) + ^ reinterpret_cast(&(*vertices_[i])); + Vertex_handle mirror; + typedef typename Vertex_handle::pointer pointer; + // mirror.set_pointer(reinterpret_cast(opp_vertex)); + mirror = Compact_container + ::s_iterator_to(*(reinterpret_cast(opp_vertex))); + return mirror; + } + void swap_vertices(const int d1, const int d2) + { + std::swap(vertices_[d1], vertices_[d2]); + std::swap(neighbors_[d1], neighbors_[d2]); + } +}; + +} //namespace CGAL + +#endif // CGAL_TDS_FULL_CELL_DEFAULT_STORAGE_POLICY_H diff --git a/include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h b/include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h new file mode 100644 index 00000000..095dfe68 --- /dev/null +++ b/include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h @@ -0,0 +1,71 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TDS_FULL_CELL_MIRROR_STORAGE_POLICY_H +#define CGAL_TDS_FULL_CELL_MIRROR_STORAGE_POLICY_H + +#include + +namespace CGAL { + +// POLICY TAGS + +struct TDS_full_cell_mirror_storage_policy {}; // Stores the mirror index of all vertices. + +template< typename Vertex_handle, typename Full_cell_handle, typename Maximal_dimension > +struct TFC_data< Vertex_handle, Full_cell_handle, Maximal_dimension, TDS_full_cell_mirror_storage_policy > +: public TFC_data< Vertex_handle, Full_cell_handle, Maximal_dimension, TDS_full_cell_default_storage_policy > +{ + typedef TFC_data< Vertex_handle, Full_cell_handle, Maximal_dimension, TDS_full_cell_default_storage_policy > Base; + typedef typename Base::Vertex_handle_array Vertex_handle_array; + typedef typename Base::Full_cell_handle_array Full_cell_handle_array; + typedef typename internal::S_or_D_array< int, typename Base::Dimen_plus > Int_array; + +private: + Int_array mirror_vertices_; + +public: + TFC_data(const int dmax) + : Base(dmax), mirror_vertices_(dmax+1) + {} + + void set_mirror_index(const int i, const int index) + { + mirror_vertices_[i] = index; + } + int mirror_index(const int i) const + { + return mirror_vertices_[i]; + } + Vertex_handle mirror_vertex(const int i, const int) const + { + return Base::neighbors_[i]->vertex(mirror_index(i)); + } + void swap_vertices(const int d1, const int d2) + { + Base::swap_vertices(d1, d2); + std::swap(mirror_vertices_[d1], mirror_vertices_[d2]); + Base::neighbors_[d1]->set_mirror_index(mirror_vertices_[d1], d1); + Base::neighbors_[d2]->set_mirror_index(mirror_vertices_[d2], d2); + } +}; + +} //namespace CGAL + +#endif // CGAL_TDS_FULL_CELL_MIRROR_STORAGE_POLICY_H diff --git a/include/gudhi_patches/CGAL/Triangulation.h b/include/gudhi_patches/CGAL/Triangulation.h new file mode 100644 index 00000000..906df92e --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation.h @@ -0,0 +1,1424 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_H +#define CGAL_TRIANGULATION_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace CGAL { + +// Iterator which iterates over vertex_handle's, but returns a point when +// dereferenced. If the current +// vertex_handle vh == vh_where_point_should_be_substituted, it returns +// "subtitute_point", otherwise, it returns vh->point() +template +class Substitute_point_in_vertex_iterator +{ + typedef typename std::iterator_traits::value_type Vertex_handle; + typedef typename Vertex_handle::value_type Vertex; + typedef typename Vertex::Point Point; + +public: + typedef Point const& result_type; // For result_of + + Substitute_point_in_vertex_iterator( + Vertex_handle vh_where_point_should_be_substituted, + Point const *subtitute_point) + : vh_where_point_should_be_substituted_(vh_where_point_should_be_substituted) + , subtitute_point_(subtitute_point) + {} + + result_type operator()(Vertex_handle vh) const + { + if (vh == vh_where_point_should_be_substituted_) + return *subtitute_point_; + else + return vh->point(); + } + +private: + Vertex_handle vh_where_point_should_be_substituted_; + Point const *subtitute_point_; + +}; + + +template < class TriangulationTraits, class TDS_ = Default > +class Triangulation +{ + typedef typename TriangulationTraits::Dimension Maximal_dimension_; + typedef typename Default::Get, + Triangulation_full_cell > + >::type TDS; + typedef Triangulation Self; + +protected: + typedef typename TriangulationTraits::Flat_orientation_d Flat_orientation_d; + typedef typename TriangulationTraits::Construct_flat_orientation_d Construct_flat_orientation_d; + typedef typename TriangulationTraits::In_flat_orientation_d In_flat_orientation_d; + + // Wrapper + struct Coaffine_orientation_d + { + boost::optional* fop; + Construct_flat_orientation_d cfo; + In_flat_orientation_d ifo; + + Coaffine_orientation_d( + boost::optional& x, + Construct_flat_orientation_d const&y, + In_flat_orientation_d const&z) + : fop(&x), cfo(y), ifo(z) {} + + template + CGAL::Orientation operator()(Iter a, Iter b) const + { + if (*fop) + return ifo(fop->get(),a,b); + *fop = cfo(a,b); + CGAL_assertion(ifo(fop->get(),a,b) == CGAL::POSITIVE); + return CGAL::POSITIVE; + } + }; + + void reset_flat_orientation() + { + if (current_dimension() == preset_flat_orientation_.first) + { + CGAL_assertion(preset_flat_orientation_.second != NULL); + flat_orientation_ = *preset_flat_orientation_.second; + } + else + flat_orientation_ = boost::none; + } + + typedef typename TriangulationTraits::Orientation_d + Orientation_d; + +public: + + typedef TriangulationTraits Geom_traits; + typedef TDS Triangulation_ds; + + typedef typename TDS::Vertex Vertex; + typedef typename TDS::Full_cell Full_cell; + typedef typename TDS::Facet Facet; + typedef typename TDS::Face Face; + + typedef Maximal_dimension_ Maximal_dimension; + typedef typename Geom_traits::Point_d Point; + + typedef typename TDS::Vertex_handle Vertex_handle; + typedef typename TDS::Vertex_iterator Vertex_iterator; + typedef typename TDS::Vertex_const_handle Vertex_const_handle; + typedef typename TDS::Vertex_const_iterator Vertex_const_iterator; + + typedef typename TDS::Full_cell_handle Full_cell_handle; + typedef typename TDS::Full_cell_iterator Full_cell_iterator; + typedef typename TDS::Full_cell_const_handle Full_cell_const_handle; + typedef typename TDS::Full_cell_const_iterator Full_cell_const_iterator; + + typedef typename TDS::Facet_iterator Facet_iterator; + + typedef typename TDS::size_type size_type; + typedef typename TDS::difference_type difference_type; + + /// The type of location a new point is found lying on + enum Locate_type + { + ON_VERTEX = 0 // simplex of dimension 0 + , IN_FACE = 1 // simplex of dimension in [ 1, |current_dimension()| - 2 ] + , IN_FACET = 2 // simplex of dimension |current_dimension()| - 1 + , IN_FULL_CELL = 3 /// simplex of dimension |current_dimension()| + , OUTSIDE_CONVEX_HULL = 4 + , OUTSIDE_AFFINE_HULL = 5 + }; + + // Finite elements iterators + + class Finiteness_predicate; + + typedef boost::filter_iterator + Finite_vertex_iterator; + typedef boost::filter_iterator + Finite_vertex_const_iterator; + typedef boost::filter_iterator + Finite_full_cell_iterator; + typedef boost::filter_iterator + Finite_full_cell_const_iterator; + typedef boost::filter_iterator + Finite_facet_iterator; + +protected: // DATA MEMBERS + + Triangulation_ds tds_; + const Geom_traits kernel_; + Vertex_handle infinity_; + mutable std::vector orientations_; + mutable boost::optional flat_orientation_; + // The user can specify a Flat_orientation_d object to be used for + // orienting simplices of a specific dimension + // (= preset_flat_orientation_.first) + // preset_flat_orientation_.first = numeric_limits::max() otherwise) + std::pair preset_flat_orientation_; + // for stochastic walk in the locate() function: + mutable Random rng_; +#ifdef CGAL_TRIANGULATION_STATISTICS + mutable unsigned long walk_size_; +#endif + +protected: // HELPER FUNCTIONS + + typedef CGAL::Iterator_project< + typename Full_cell::Vertex_handle_const_iterator, + internal::Triangulation::Point_from_vertex_handle + > Point_const_iterator; + + Point_const_iterator points_begin(Full_cell_const_handle c) const + { return Point_const_iterator(c->vertices_begin()); } + Point_const_iterator points_end(Full_cell_const_handle c) const + { return Point_const_iterator(c->vertices_end()); } + Point_const_iterator points_begin(Full_cell_handle c) const + { return Point_const_iterator(c->vertices_begin()); } + Point_const_iterator points_end(Full_cell_handle c) const + { return Point_const_iterator(c->vertices_end()); } + +public: + + // FACETS OPERATIONS + + Full_cell_handle full_cell(const Facet & f) const + { + return tds().full_cell(f); + } + + int index_of_covertex(const Facet & f) const + { + return tds().index_of_covertex(f); + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UTILITIES + + // A co-dimension 2 sub-simplex. called a Rotor because we can rotate + // the two "covertices" around the sub-simplex. Useful for traversing the + // boundary of a hole. NOT DOCUMENTED + typedef cpp11::tuple Rotor; + + // Commented out because it was causing "internal compiler error" in MSVC + /*Full_cell_handle full_cell(const Rotor & r) const // NOT DOCUMENTED + { + return cpp11::get<0>(r); + } + int index_of_covertex(const Rotor & r) const // NOT DOCUMENTED + { + return cpp11::get<1>(r); + } + int index_of_second_covertex(const Rotor & r) const // NOT DOCUMENTED + { + return cpp11::get<2>(r); + }*/ + Rotor rotate_rotor(Rotor & r) // NOT DOCUMENTED... + { + int opposite = cpp11::get<0>(r)->mirror_index(cpp11::get<1>(r)); + Full_cell_handle s = cpp11::get<0>(r)->neighbor(cpp11::get<1>(r)); + int new_second = s->index(cpp11::get<0>(r)->vertex(cpp11::get<2>(r))); + return Rotor(s, new_second, opposite); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - CREATION / CONSTRUCTORS + + Triangulation(int dim, const Geom_traits &k = Geom_traits()) + : tds_(dim) + , kernel_(k) + , infinity_() + , preset_flat_orientation_((std::numeric_limits::max)(), + (Flat_orientation_d*) NULL) + , rng_((long)0) +#ifdef CGAL_TRIANGULATION_STATISTICS + ,walk_size_(0) +#endif + { + clear(); + } + + // With this constructor, + // the user can specify a Flat_orientation_d object to be used for + // orienting simplices of a specific dimension + // (= preset_flat_orientation_.first) + // It it used for by dark triangulations created by DT::remove + Triangulation( + int dim, + const std::pair &preset_flat_orientation, + const Geom_traits k = Geom_traits()) + : tds_(dim) + , kernel_(k) + , infinity_() + , preset_flat_orientation_(preset_flat_orientation) + , rng_((long)0) +#ifdef CGAL_TRIANGULATION_STATISTICS + ,walk_size_(0) +#endif + { + clear(); + } + + Triangulation(const Triangulation & t2) + : tds_(t2.tds_) + , kernel_(t2.kernel_) + , infinity_() + , preset_flat_orientation_((std::numeric_limits::max)(), + (Flat_orientation_d*) NULL) + , rng_(t2.rng_) +#ifdef CGAL_TRIANGULATION_STATISTICS + ,walk_size_(t2.walk_size_) +#endif + { + // We find the vertex at infinity by scanning the vertices of both + // triangulations. This works because Compact_container garantees that + // the vertices in the copy (*this) are stored in the same order as in + // the original triangulation (t2) + infinity_ = vertices_begin(); + Vertex_const_iterator inf2 = t2.vertices_begin(); + while( inf2 != t2.infinite_vertex() ) + { + ++infinity_; + ++inf2; + } + // A full_cell has at most 1 + maximal_dimension() facets: + orientations_.resize(1 + maximal_dimension()); + // Our coaffine orientation predicates HAS state member variables + reset_flat_orientation(); + } + + ~Triangulation() {} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ACCESS FUNCTIONS + + /* These three function are no longer needed since we do not use them anymore + in the Delaunay_triangulation::remove. *But*, they may reappear in the future + if we manage to passe the information that flags/TDS_data is available or not + for marking simplices in Delaunay_triangulation::remove. This would be useful + to make it a little faster, instead of binary searching if a simplex is marked + or not... + // NOT DOCUMENTED -- + bool get_visited(Full_cell_handle s) const + { + return tds().get_visited(s); + } + // NOT DOCUMENTED -- + bool get_visited(Full_cell_const_handle s) const + { + return tds().get_visited(s); + } + + // NOT DOCUMENTED -- + void set_visited(Full_cell_handle s, bool b) const + { + tds().set_visited(s, b); + } */ + + Coaffine_orientation_d coaffine_orientation_predicate() const + { + return Coaffine_orientation_d ( + flat_orientation_, + geom_traits().construct_flat_orientation_d_object(), + geom_traits().in_flat_orientation_d_object() + ); + } + + const Triangulation_ds & tds() const + { + return tds_; + } + + Triangulation_ds & tds() + { + return tds_; + } + + const Geom_traits & geom_traits() const + { + return kernel_; + } + + int maximal_dimension() const { return tds().maximal_dimension(); } + int current_dimension() const { return tds().current_dimension(); } + + bool empty() const + { + return current_dimension() == -1; + } + + size_type number_of_vertices() const + { + return tds().number_of_vertices() - 1; + } + + size_type number_of_full_cells() const + { + return tds().number_of_full_cells(); + } + + Vertex_handle infinite_vertex() const + { + return infinity_; + } + + Full_cell_handle infinite_full_cell() const + { + CGAL_assertion(infinite_vertex()->full_cell()->has_vertex(infinite_vertex())); + return infinite_vertex()->full_cell(); + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - NON CONSTANT-TIME ACCESS FUNCTIONS + + size_type number_of_finite_full_cells() const + { + Full_cell_const_iterator s = full_cells_begin(); + size_type result = number_of_full_cells(); + for( ; s != full_cells_end(); ++s ) + { + if( is_infinite(s) ) + --result; + } + return result; + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TRAVERSAL + + Vertex_iterator vertices_begin() { return tds().vertices_begin(); } + Vertex_iterator vertices_end() { return tds().vertices_end(); } + + Vertex_const_iterator vertices_begin() const { return tds().vertices_begin(); } + Vertex_const_iterator vertices_end() const { return tds().vertices_end(); } + + Finite_vertex_iterator finite_vertices_begin() + { return Finite_vertex_iterator(Finiteness_predicate(*this), vertices_begin(), vertices_end()); } + Finite_vertex_iterator finite_vertices_end() + { return Finite_vertex_iterator(Finiteness_predicate(*this), vertices_end(), vertices_end()); } + Finite_vertex_const_iterator finite_vertices_begin() const + { return Finite_vertex_const_iterator(Finiteness_predicate(*this), vertices_begin(), vertices_end()); } + Finite_vertex_const_iterator finite_vertices_end() const + { return Finite_vertex_const_iterator(Finiteness_predicate(*this), vertices_end(), vertices_end()); } + + Full_cell_iterator full_cells_begin() { return tds().full_cells_begin(); } + Full_cell_iterator full_cells_end() { return tds().full_cells_end(); } + + Full_cell_const_iterator full_cells_begin() const { return tds().full_cells_begin(); } + Full_cell_const_iterator full_cells_end() const { return tds().full_cells_end(); } + + Finite_full_cell_iterator finite_full_cells_begin() + { return Finite_full_cell_iterator(Finiteness_predicate(*this), full_cells_begin(), full_cells_end()); } + Finite_full_cell_iterator finite_full_cells_end() + { return Finite_full_cell_iterator(Finiteness_predicate(*this), full_cells_end(), full_cells_end()); } + Finite_full_cell_const_iterator finite_full_cells_begin() const + { return Finite_full_cell_const_iterator(Finiteness_predicate(*this), full_cells_begin(), full_cells_end()); } + Finite_full_cell_const_iterator finite_full_cells_end() const + { return Finite_full_cell_const_iterator(Finiteness_predicate(*this), full_cells_end(), full_cells_end()); } + + Facet_iterator facets_begin() { return tds().facets_begin(); } + Facet_iterator facets_end() { return tds().facets_end(); } + Facet_iterator finite_facets_begin() + { return Finite_facet_iterator(Finiteness_predicate(*this), facets_begin(), facets_end()); } + Facet_iterator finite_facets_end() + { return Finite_facet_iterator(Finiteness_predicate(*this), facets_end(), facets_end()); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SOME PREDICATE FUNCTORS + + class Finiteness_predicate + { + const Self & t_; + public: + Finiteness_predicate(const Self & t) : t_(t) {} + template < class T > + bool operator()(const T & t) const + { + return ! t_.is_infinite(t); + } + }; + + class Point_equality_predicate + { + const Point & o_; + public: + Point_equality_predicate(const Point & o) : o_(o) {} + bool operator()(const Point & o) const { return (o == o_ );} + }; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SIMPLE QUERIES +/* + bool is_vertex(const Point & p, Vertex_handle & v, Full_cell_handle hint = Full_cell_handle()) const + { + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, hint); + if( ON_VERTEX == lt ) + { + v = s->vertex(f.index(0)); + return true; + } + return false; + } + + bool is_vertex(Vertex_const_handle v) const + { + return tds().is_vertex(v); + } + + bool is_full_cell(Full_cell_const_handle s) const + { + return tds().is_full_cell(s); + } +*/ + + bool is_infinite(Vertex_const_handle v) const + { + CGAL_precondition(Vertex_const_handle() != v); + return (infinite_vertex() == v); + } + + bool is_infinite(const Vertex & v) const /* internal use, not documented */ + { + return (&(*infinite_vertex()) == &v); + } + + bool is_infinite(Full_cell_const_handle s) const + { + CGAL_precondition(Full_cell_const_handle() != s); + return is_infinite(*s); + } + bool is_infinite(const Full_cell & s) const /* internal use, not documented */ + { + for(int i = 0; i <= current_dimension(); ++i) + if( is_infinite(s.vertex(i)) ) + return true; + return false; + } + bool is_infinite(const Facet & ft) const + { + Full_cell_const_handle s = full_cell(ft); + CGAL_precondition(s != Full_cell_const_handle()); + if( is_infinite(s) ) + return (s->vertex(index_of_covertex(ft)) != infinite_vertex()); + return false; + } + + bool is_infinite(const Face & f) const + { + Full_cell_const_handle s = f.full_cell(); + CGAL_precondition(s != Full_cell_const_handle()); + if( is_infinite(s) ) + { + Vertex_handle v; + for( int i(0); i<= f.face_dimension(); ++i) + if ( is_infinite( f.vertex(i) )) return true; + } + return false; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ELEMENT GATHERING + + + template< typename OutputIterator > + OutputIterator incident_full_cells(const Face & f, OutputIterator out) const + { + return tds().incident_full_cells(f, out); + } + template< typename OutputIterator > + OutputIterator incident_full_cells(Vertex_const_handle v, OutputIterator out) const + { + return tds().incident_full_cells(v, out); + } + template< typename OutputIterator > + OutputIterator star(const Face & f, OutputIterator out) const + { + return tds().star(f, out); + } + + template< typename OutputIterator > + OutputIterator incident_faces(Vertex_const_handle v, int d, OutputIterator out) const + { + return tds().incident_faces(v, d, out); + } + /* + template< typename OutputIterator, class Comparator > + OutputIterator incident_upper_faces( Vertex_const_handle v, int d, + OutputIterator out, Comparator cmp = Comparator()) + { + return tds().incident_upper_faces(v, d, out, cmp); + } + template< typename OutputIterator > + OutputIterator incident_upper_faces( Vertex_const_handle v, int d, + OutputIterator out) + { // FIXME: uncomment this function, since it uses a comparator specific to + // *geometric* triangulation (taking infinite vertex into account) + internal::Triangulation::Compare_vertices_for_upper_face cmp(*this); + return tds().incident_upper_faces(v, d, out, cmp); + } + */ + Orientation orientation(Full_cell_const_handle s, bool in_is_valid = false) const + { + if( ! in_is_valid ) + CGAL_assertion( ! is_infinite(s) ); + if( 0 == current_dimension() ) + return POSITIVE; + if( current_dimension() == maximal_dimension() ) + { + Orientation_d ori = geom_traits().orientation_d_object(); + return ori(points_begin(s), points_begin(s) + 1 + current_dimension()); + } + else + { + return coaffine_orientation_predicate()(points_begin(s), points_begin(s) + 1 + current_dimension()); + } + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UPDATE OPERATIONS + + void clear() + { + tds_.clear(); + infinity_ = tds().insert_increase_dimension(); + // A full_cell has at most 1 + maximal_dimension() facets: + orientations_.resize(1 + maximal_dimension()); + // Our coaffine orientation predicates HAS state member variables + reset_flat_orientation(); +#ifdef CGAL_TRIANGULATION_STATISTICS + walk_size_ = 0; +#endif + } + + void set_current_dimension(int d) + { + tds().set_current_dimension(d); + } + + Full_cell_handle new_full_cell() + { + return tds().new_full_cell(); + } + + Vertex_handle new_vertex() + { + return tds().new_vertex(); + } + + Vertex_handle new_vertex(const Point & p) + { + return tds().new_vertex(p); + } + + void set_neighbors(Full_cell_handle s, int i, Full_cell_handle s1, int j) + { + tds().set_neighbors(s, i, s1, j); + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + + bool is_valid(bool = false, int = 0) const; + bool are_incident_full_cells_valid(Vertex_const_handle, bool = false, int = 0) const; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - POINT LOCATION + +protected: + template< typename OrientationPredicate > + Full_cell_handle do_locate(const Point &, Locate_type &, Face &, Facet &, + Full_cell_handle start, + const OrientationPredicate & o) const; +public: + Full_cell_handle locate(const Point &, Locate_type &, Face &, Facet &, + Full_cell_handle start = Full_cell_handle()) const; + Full_cell_handle locate(const Point &, Locate_type &, Face &, Facet &, + Vertex_handle) const; + Full_cell_handle locate(const Point & p, Full_cell_handle s = Full_cell_handle()) const; + Full_cell_handle locate(const Point & p, Vertex_handle v) const; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + + Vertex_handle contract_face(const Point &, const Face &); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - POINT INSERTION + + template< typename ForwardIterator > + size_type insert(ForwardIterator start, ForwardIterator end) + { + size_type n = number_of_vertices(); + std::vector points(start, end); + spatial_sort(points.begin(), points.end(), geom_traits()); + Full_cell_handle hint = Full_cell_handle(); + typename std::vector::const_iterator s = points.begin(); + while( s != points.end() ) + { + hint = insert(*s++, hint)->full_cell(); + } + return number_of_vertices() - n; + } + Vertex_handle insert(const Point &, Locate_type, const Face &, const Facet &, Full_cell_handle); + Vertex_handle insert(const Point &, Full_cell_handle start = Full_cell_handle()); + Vertex_handle insert(const Point &, Vertex_handle); + template< typename ForwardIterator > + Vertex_handle insert_in_hole(const Point & p, ForwardIterator start, ForwardIterator end, const Facet & ft) + { + Emptyset_iterator out; + return insert_in_hole(p, start, end, ft, out); + } + template< typename ForwardIterator, typename OutputIterator > + Vertex_handle insert_in_hole(const Point & p, ForwardIterator start, ForwardIterator end, const Facet & ft, + OutputIterator out) + { + Vertex_handle v = tds().insert_in_hole(start, end, ft, out); + v->set_point(p); + return v; + } + Vertex_handle insert_in_face(const Point &, const Face &); + Vertex_handle insert_in_facet(const Point &, const Facet &); + Vertex_handle insert_in_full_cell(const Point &, Full_cell_handle); + Vertex_handle insert_outside_convex_hull_1(const Point &, Full_cell_handle); + Vertex_handle insert_outside_convex_hull(const Point &, Full_cell_handle); + Vertex_handle insert_outside_affine_hull(const Point &); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - FACET-TRAVERSAL PREDICATES + + template< typename OrientationPredicate > + class Outside_convex_hull_traversal_predicate + { + Triangulation & t_; + const Point & p_; + OrientationPredicate const& ori_; + int cur_dim_; + public: + Outside_convex_hull_traversal_predicate(Triangulation & t, const Point & p, + OrientationPredicate const& ori) + : t_(t), p_(p), ori_(ori), cur_dim_(t.current_dimension()) {} + // FUTURE change parameter to const reference + bool operator()(Facet f) const + { + Full_cell_handle s = t_.full_cell(f); + const int i = t_.index_of_covertex(f); + Full_cell_handle n = s->neighbor(i); + if( ! t_.is_infinite(n) ) + return false; + int inf_v_index = n->index(t_.infinite_vertex()); + n->vertex(inf_v_index)->set_point(p_); + bool ok = (POSITIVE == ori_(t_.points_begin(n), t_.points_begin(n) + cur_dim_ + 1)); + return ok; + } + }; + + // make sure all full_cells have positive orientation + void reorient_full_cells(); + +protected: + // This is used in the |remove(v)| member function to manage sets of Full_cell_handles + template< typename FCH > + struct Full_cell_set : public std::vector + { + typedef std::vector Base_set; + using Base_set::begin; + using Base_set::end; + void make_searchable() + { // sort the full cell handles + std::sort(begin(), end()); + } + bool contains(const FCH & fch) const + { + return std::binary_search(begin(), end(), fch); + } + bool contains_1st_and_not_2nd(const FCH & fst, const FCH & snd) const + { + return ( ! contains(snd) ) && ( contains(fst) ); + } + }; + + void display_all_full_cells__debugging() const + { + std::cerr << "ALL FULL CELLS:" << std::endl; + for (Full_cell_const_iterator cit = full_cells_begin() ; + cit != full_cells_end() ; ++cit ) + { + std::cerr << std::hex << &*cit << ": "; + for (int jj = 0 ; jj <= current_dimension() ; ++jj) + std::cerr << (is_infinite(cit->vertex(jj)) ? 0xFFFFFFFF : (unsigned int)&*cit->vertex(jj)) << " - "; + std::cerr << std::dec << std::endl; + } + std::cerr << std::endl; + } + + +}; // Triangulation<...> + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +// CLASS MEMBER FUNCTIONS + +template < class TT, class TDS > +void +Triangulation +::reorient_full_cells() +{ + if( current_dimension() < 1 ) + return; + + Full_cell_iterator sit = full_cells_begin(); + Full_cell_iterator send = full_cells_end(); + for ( ; sit != send ; ++sit) + { + if( ! (is_infinite(sit) && (1 == current_dimension())) ) + { + sit->swap_vertices(current_dimension() - 1, current_dimension()); + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - THE REMOVAL METHODS + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::contract_face(const Point & p, const Face & f) +{ + CGAL_precondition( ! is_infinite(f) ); + Vertex_handle v = tds().contract_face(f); + v->set_point(p); + CGAL_expensive_postcondition_msg(are_incident_full_cells_valid(v), "new point is not where it should be"); + return v; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - THE INSERTION METHODS + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert(const Point & p, Locate_type lt, const Face & f, const Facet & ft, Full_cell_handle s) +{ + switch( lt ) + { + case IN_FULL_CELL: + return insert_in_full_cell(p, s); + break; + case OUTSIDE_CONVEX_HULL: + return insert_outside_convex_hull(p, s); + break; + case OUTSIDE_AFFINE_HULL: + return insert_outside_affine_hull(p); + break; + case IN_FACET: + { + return insert_in_facet(p, ft); + break; + } + case IN_FACE: + return insert_in_face(p, f); + break; + case ON_VERTEX: + s->vertex(f.index(0))->set_point(p); + return s->vertex(f.index(0)); + break; + } + CGAL_assertion(false); + return Vertex_handle(); +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert(const Point & p, Full_cell_handle start) +{ + Locate_type lt; + Face f(maximal_dimension()); + Facet ft; + Full_cell_handle s = locate(p, lt, f, ft, start); + return insert(p, lt, f, ft, s); +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert(const Point & p, Vertex_handle v) +{ + if( Vertex_handle() == v ) + v = infinite_vertex(); + return insert(p, v->full_cell()); +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_in_face(const Point & p, const Face & f) +{ + CGAL_precondition( ! is_infinite(f) ); + Vertex_handle v = tds().insert_in_face(f); + v->set_point(p); + return v; +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_in_facet(const Point & p, const Facet & ft) +{ + CGAL_precondition( ! is_infinite(ft) ); + Vertex_handle v = tds().insert_in_facet(ft); + v->set_point(p); + return v; +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_in_full_cell(const Point & p, Full_cell_handle s) +{ + CGAL_precondition( ! is_infinite(s) ); + Vertex_handle v = tds().insert_in_full_cell(s); + v->set_point(p); + return v; +} + +// NOT DOCUMENTED... +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_outside_convex_hull_1(const Point & p, Full_cell_handle s) +{ + // This is a special case for dimension 1, because in that case, the right + // infinite full_cell is not correctly oriented... (sice its first vertex is the + // infinite one... + CGAL_precondition( is_infinite(s) ); + CGAL_precondition( 1 == current_dimension() ); + Vertex_handle v = tds().insert_in_full_cell(s); + v->set_point(p); + return v; +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_outside_convex_hull(const Point & p, Full_cell_handle s) +{ + if( 1 == current_dimension() ) + { + return insert_outside_convex_hull_1(p, s); + } + CGAL_precondition( is_infinite(s) ); + CGAL_assertion( current_dimension() >= 2 ); + std::vector simps; + simps.reserve(64); + std::back_insert_iterator > out(simps); + if( current_dimension() < maximal_dimension() ) + { + Coaffine_orientation_d ori = coaffine_orientation_predicate(); + Outside_convex_hull_traversal_predicate + ochtp(*this, p, ori); + tds().gather_full_cells(s, ochtp, out); + } + else + { + Orientation_d ori = geom_traits().orientation_d_object(); + Outside_convex_hull_traversal_predicate + ochtp(*this, p, ori); + tds().gather_full_cells(s, ochtp, out); + } + int inf_v_index = s->index(infinite_vertex()); + Vertex_handle v = insert_in_hole( + p, simps.begin(), simps.end(), Facet(s, inf_v_index)); + return v; +} + +template < class TT, class TDS > +typename Triangulation::Vertex_handle +Triangulation +::insert_outside_affine_hull(const Point & p) +{ + CGAL_precondition( current_dimension() < maximal_dimension() ); + Vertex_handle v = tds().insert_increase_dimension(infinite_vertex()); + // reset the orientation predicate: + reset_flat_orientation(); + v->set_point(p); + if( current_dimension() >= 1 ) + { + Full_cell_handle inf_v_cell = infinite_vertex()->full_cell(); + int inf_v_index = inf_v_cell->index(infinite_vertex()); + Full_cell_handle s = inf_v_cell->neighbor(inf_v_index); + Orientation o = orientation(s); + CGAL_assertion( COPLANAR != o ); + if( NEGATIVE == o ) + reorient_full_cells(); + + + // We just inserted the second finite point and the right infinite + // cell is like : (inf_v, v), but we want it to be (v, inf_v) to be + // consistent with the rest of the cells + if (current_dimension() == 1) + { + // Is "inf_v_cell" the right infinite cell? + // Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices( + current_dimension() - 1, current_dimension()); + } + // Otherwise, let's find the right infinite cell + else + { + inf_v_cell = inf_v_cell->neighbor((inf_v_index + 1) % 2); + inf_v_index = inf_v_cell->index(infinite_vertex()); + // Is "inf_v_cell" the right infinite cell? + // Then inf_v_index should be 1 + if (inf_v_cell->neighbor(inf_v_index)->index(inf_v_cell) == 0 + && inf_v_index == 0) + { + inf_v_cell->swap_vertices( + current_dimension() - 1, current_dimension()); + } + } + } + } + return v; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - THE MAIN LOCATE(...) FUNCTION + +template < class TT, class TDS > +template< typename OrientationPredicate > +typename Triangulation::Full_cell_handle +Triangulation +::do_locate(const Point & p, // query point + Locate_type & loc_type,// type of result (full_cell, face, vertex) + Face & face,// the face containing the query in its interior (when appropriate) + Facet & facet,// the facet containing the query in its interior (when appropriate) + Full_cell_handle start, // starting full_cell for the walk + OrientationPredicate const& orientation_pred + ) const +{ + const int cur_dim = current_dimension(); + + if( cur_dim == -1 ) + { + loc_type = OUTSIDE_AFFINE_HULL; + return Full_cell_handle(); + } + else if( cur_dim == 0 ) + { + Vertex_handle vit = infinite_full_cell()->neighbor(0)->vertex(0); + if( EQUAL != geom_traits().compare_lexicographically_d_object()(p, vit->point()) ) + { + loc_type = OUTSIDE_AFFINE_HULL; + return Full_cell_handle(); + } + else + { + loc_type = ON_VERTEX; + face.set_full_cell(vit->full_cell()); + face.set_index(0, 0); + return vit->full_cell(); + } + } + + Full_cell_handle s; + + // if we don't know where to start, we start from any bounded full_cell + if( Full_cell_handle() == start ) + { + // THE HACK THAT NOBODY SHOULD DO... BUT DIFFICULT TO WORK AROUND + // THIS... TODO: WORK AROUND IT + Full_cell_handle inf_c = const_cast(this)->infinite_full_cell(); + int inf_v_index = inf_c->index(infinite_vertex()); + s = inf_c->neighbor(inf_v_index); + } + else + { + s = start; + if( is_infinite(s) ) + { + int inf_v_index = s->index(infinite_vertex()); + s = s->neighbor(inf_v_index); + } + } + + // Check if query |p| is outside the affine hull + if( cur_dim < maximal_dimension() ) + { + if( ! geom_traits().contained_in_affine_hull_d_object()( + points_begin(s), + points_begin(s) + current_dimension() + 1, + p) ) + { + loc_type = OUTSIDE_AFFINE_HULL; + return Full_cell_handle(); + } + } + + // we remember the |previous|ly visited full_cell to avoid the evaluation + // of one |orientation| predicate + Full_cell_handle previous = Full_cell_handle(); + bool full_cell_not_found = true; + while(full_cell_not_found) // we walk until we locate the query point |p| + { + #ifdef CGAL_TRIANGULATION_STATISTICS + ++walk_size_; + #endif + // For the remembering stochastic walk, we need to start trying + // with a random index: + int j, i = rng_.get_int(0, cur_dim); + // we check |p| against all the full_cell's hyperplanes in turn + + for(j = 0; j <= cur_dim; ++j, i = (i + 1) % (cur_dim + 1) ) + { + Full_cell_handle next = s->neighbor(i); + if( previous == next ) + { // no need to compute the orientation, we already know it + orientations_[i] = POSITIVE; + continue; // go to next full_cell's facet + } + + Substitute_point_in_vertex_iterator< + typename Full_cell::Vertex_handle_const_iterator> + spivi(s->vertex(i), &p); + + orientations_[i] = orientation_pred( + boost::make_transform_iterator(s->vertices_begin(), spivi), + boost::make_transform_iterator(s->vertices_begin() + cur_dim + 1, + spivi)); + + if( orientations_[i] != NEGATIVE ) + { + // from this facet's point of view, we are inside the + // full_cell or on its boundary, so we continue to next facet + continue; + } + + // At this point, we know that we have to jump to the |next| + // full_cell because orientation_[i] == NEGATIVE + previous = s; + s = next; + if( is_infinite(next) ) + { // we have arrived OUTSIDE the convex hull of the triangulation, + // so we stop the search + full_cell_not_found = false; + loc_type = OUTSIDE_CONVEX_HULL; + face.set_full_cell(s); + } + break; + } // end of the 'for' loop + if( ( cur_dim + 1 ) == j ) // we found the full_cell containing |p| + full_cell_not_found = false; + } + // Here, we know in which full_cell |p| is in. + // We now check more precisely where |p| landed: + // vertex, facet, face or full_cell. + if( ! is_infinite(s) ) + { + face.set_full_cell(s); + int num(0); + int verts(0); + for(int i = 0; i < cur_dim; ++i) + { + if( orientations_[i] == COPLANAR ) + { + ++num; + facet = Facet(s, i); + } + else + face.set_index(verts++, i); + } + //-- We could put the if{}else{} below in the loop above, but then we would + // need to test if (verts < cur_dim) many times... we do it only once + // here: + if( orientations_[cur_dim] == COPLANAR ) + { + ++num; + facet = Facet(s, cur_dim); + } + else if( verts < cur_dim ) + face.set_index(verts, cur_dim); + //-- end of remark above // + if( 0 == num ) + { + loc_type = IN_FULL_CELL; + face.clear(); + } + else if( cur_dim == num ) + loc_type = ON_VERTEX; + else if( 1 == num ) + loc_type = IN_FACET; + else + loc_type = IN_FACE; + } + return s; +} + +template < class TT, class TDS > +typename Triangulation::Full_cell_handle +Triangulation +::locate( const Point & p, // query point + Locate_type & loc_type,// type of result (full_cell, face, vertex) + Face & face,// the face containing the query in its interior (when appropriate) + Facet & facet,// the facet containing the query in its interior (when appropriate) + Full_cell_handle start// starting full_cell for the walk + ) const +{ + if( current_dimension() == maximal_dimension() ) + { + Orientation_d ori = geom_traits().orientation_d_object(); + return do_locate(p, loc_type, face, facet, start, ori); + } + else + return do_locate(p, loc_type, face, facet, start, coaffine_orientation_predicate()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - the locate(...) variants + +template < class TT, class TDS > +typename Triangulation::Full_cell_handle +Triangulation +::locate( const Point & p, + Locate_type & loc_type, + Face & face, + Facet & facet, + Vertex_handle start) const +{ + if( Vertex_handle() == start ) + start = infinite_vertex(); + return locate(p, loc_type, face, facet, start->full_cell()); +} + +template < class TT, class TDS > +typename Triangulation::Full_cell_handle +Triangulation +::locate(const Point & p, Full_cell_handle s) const +{ + Locate_type lt; + Face face(maximal_dimension()); + Facet facet; + return locate(p, lt, face, facet, s); +} + +template < class TT, class TDS > +typename Triangulation::Full_cell_handle +Triangulation +::locate(const Point & p, Vertex_handle v) const +{ + if( Vertex_handle() != v ) + v = infinite_vertex(); + return this->locate(p, v->full_cell()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY + +template < class TT, class TDS > +bool +Triangulation +::is_valid(bool verbose, int level) const +{ + if( ! tds().is_valid(verbose, level) ) + return false; + + Full_cell_const_iterator c; + if( current_dimension() < 0 ) + return true; + Orientation o; + for( c = full_cells_begin(); c != full_cells_end(); ++c ) + { + if( is_infinite(c) ) + { + if( current_dimension() > 1 ) + { + int i = c->index( infinite_vertex() ); + Full_cell_handle n = c->neighbor(i); + infinite_vertex()->set_point(n->vertex(c->mirror_index(i))->point()); + o = - orientation(c, true); + } + else + o = POSITIVE; + } + else + o = orientation(c, true); + if( NEGATIVE == o ) + { + if( verbose ) CGAL_warning_msg(false, "full_cell is not correctly oriented"); + return false; + } + if( COPLANAR == o ) + { + if( verbose ) CGAL_warning_msg(false, "full_cell is flat"); + return false; + } + } + return true; +} + +template < class TT, class TDS > +bool Triangulation::are_incident_full_cells_valid(Vertex_const_handle v, bool verbose, int) const +{ + if( current_dimension() <= 0 ) + return true; + typedef std::vector Simps; + Simps simps; + simps.reserve(64); + std::back_insert_iterator out(simps); + incident_full_cells(v, out); + typename Simps::const_iterator sit = simps.begin(); + for( ; sit != simps.end(); ++sit ) + { + if( is_infinite(*sit) ) + continue; + Orientation o = orientation(*sit); + if( NEGATIVE == o ) + { + if( verbose ) CGAL_warning_msg(false, "full_cell is not correctly oriented"); + return false; + } + if( COPLANAR == o ) + { + if( verbose ) CGAL_warning_msg(false, "full_cell is flat"); + return false; + } + } + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS: + +template < class TT, class TDS > +std::istream & +operator>>(std::istream & is, Triangulation & tr) + // reads : + // - the dimensions (maximal and current) + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of full_cells + // - the full_cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each full_cell + // - the neighbors of each full_cell by their index in the preceding list +{ + typedef Triangulation T; + typedef typename T::Vertex_handle Vertex_handle; + + // read current dimension and number of vertices + size_t n; + int cd; + if( is_ascii(is) ) + is >> cd >> n; + else + { + read(is, cd); + read(is, n, io_Read_write()); + } + + CGAL_assertion_msg( cd <= tr.maximal_dimension(), "input Triangulation has too high dimension"); + + tr.clear(); + tr.set_current_dimension(cd); + + if( n == 0 ) + return is; + + std::vector vertices; + vertices.resize(n+1); + vertices[0] = tr.infinite_vertex(); + is >> (*vertices[0]); + + // read the vertices: + size_t i(1); + while( i <= n ) + { + vertices[i] = tr.new_vertex(); + is >> (*vertices[i]); // read a vertex + ++i; + } + + // now, read the combinatorial information + return tr.tds().read_full_cells(is, vertices); +} + +template < class TT, class TDS > +std::ostream & +operator<<(std::ostream & os, const Triangulation & tr) + // writes : + // - the dimensions (maximal and current) + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of full_cells + // - the full_cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each full_cell + // - the neighbors of each full_cell by their index in the preceding list +{ + typedef Triangulation T; + typedef typename T::Vertex_const_handle Vertex_handle; + typedef typename T::Vertex_const_iterator Vertex_iterator; + + // outputs dimensions and number of vertices + size_t n = tr.number_of_vertices(); + if( is_ascii(os) ) + os << tr.current_dimension() << std::endl << n << std::endl; + else + { + write(os, tr.current_dimension()); + write(os, n, io_Read_write()); + } + + if( n == 0 ) + return os; + + size_t i(0); + // write the vertices + std::map index_of_vertex; + + // infinite vertex has index 0 (among all the vertices) + index_of_vertex[tr.infinite_vertex()] = i++; + os << *tr.infinite_vertex(); + for( Vertex_iterator it = tr.vertices_begin(); it != tr.vertices_end(); ++it ) + { + if( tr.is_infinite(it) ) + continue; + os << *it; // write the vertex + index_of_vertex[it] = i++; + } + CGAL_assertion( i == n+1 ); + + // output the combinatorial information + return tr.tds().write_full_cells(os, index_of_vertex); +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_H diff --git a/include/gudhi_patches/CGAL/Triangulation_data_structure.h b/include/gudhi_patches/CGAL/Triangulation_data_structure.h new file mode 100644 index 00000000..2493c712 --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_data_structure.h @@ -0,0 +1,1603 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_DATA_STRUCTURE_H +#define CGAL_TRIANGULATION_DATA_STRUCTURE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace CGAL { + +template< class Dimen, + class Vb = Default, + class Fcb = Default > +class Triangulation_data_structure +{ + typedef Triangulation_data_structure Self; + typedef typename Default::Get >::type V_base; + typedef typename Default::Get >::type FC_base; + +public: + typedef typename V_base::template Rebind_TDS::Other Vertex; /* Concept */ + typedef typename FC_base::template Rebind_TDS::Other Full_cell; /* Concept */ + + // Tools to change the Vertex and Cell types of the TDS. + template < typename Vb2 > + struct Rebind_vertex { + typedef Triangulation_data_structure Other; + }; + + template < typename Fcb2 > + struct Rebind_full_cell { + typedef Triangulation_data_structure Other; + }; + + + + // we want to store an object of this class in every Full_cell: + class Full_cell_data + { + unsigned char bits_; + public: + Full_cell_data() : bits_(0) {} + Full_cell_data(const Full_cell_data & fcd) : bits_(fcd.bits_) {} + + void clear() { bits_ = 0; } + void mark_visited() { bits_ = 1; } + void clear_visited() { bits_ = 0; } + + bool is_clear() const { return bits_ == 0; } + bool is_visited() const { return bits_ == 1; } + // WARNING: if we use more bits and several bits can be set at once, + // then make sure to use bitwise operation above, instead of direct + // affectation. + }; + +protected: + typedef Compact_container Vertex_container; + typedef Compact_container Full_cell_container; + +public: + typedef Dimen Maximal_dimension; + + typedef typename Vertex_container::size_type size_type; /* Concept */ + typedef typename Vertex_container::difference_type difference_type; /* Concept */ + + typedef typename Vertex_container::iterator Vertex_handle; /* Concept */ + typedef typename Vertex_container::iterator Vertex_iterator; /* Concept */ + typedef typename Vertex_container::const_iterator Vertex_const_handle; + typedef typename Vertex_container::const_iterator Vertex_const_iterator; + + typedef typename Full_cell_container::iterator Full_cell_handle; /* Concept */ + typedef typename Full_cell_container::iterator Full_cell_iterator; /* Concept */ + typedef typename Full_cell_container::const_iterator Full_cell_const_handle; + typedef typename Full_cell_container::const_iterator Full_cell_const_iterator; + + typedef internal::Triangulation:: + Triangulation_ds_facet_iterator Facet_iterator; /* Concept */ + + /* The 2 types defined below, |Facet| and |Rotor| are used when traversing + the boundary `B' of the union of a set of full cells. |Rotor| makes it + easy to rotate around itself, in the search of neighbors in `B' (see + |rotate_rotor| and |insert_in_tagged_hole|) */ + + // A co-dimension 1 sub-simplex. + class Facet /* Concept */ + { + Full_cell_handle full_cell_; + int index_of_covertex_; + public: + Facet() : full_cell_(), index_of_covertex_(0) {} + Facet(Full_cell_handle f, int i) : full_cell_(f), index_of_covertex_(i) {} + Full_cell_handle full_cell() const { return full_cell_; } + int index_of_covertex() const { return index_of_covertex_; } + }; + + // A co-dimension 2 sub-simplex. called a Rotor because we can rotate + // the two "covertices" around the sub-simplex. Useful for traversing the + // boundary of a hole. NOT DOCUMENTED + class Rotor : public Facet + { + int index_of_second_covertex_; + public: + Rotor() : Facet(), index_of_second_covertex_(0) {} + Rotor(Full_cell_handle f, int first, int second) : Facet(f, first), index_of_second_covertex_(second) {} + int index_of_second_covertex() const { return index_of_second_covertex_; } + }; + + typedef Triangulation_face Face; /* Concept */ + +protected: // DATA MEMBERS + + int dmax_, dcur_; // dimension of the current triangulation + Vertex_container vertices_; // list of all vertices + Full_cell_container full_cells_; // list of all full cells + +private: + + void clean_dynamic_memory() + { + vertices_.clear(); + full_cells_.clear(); + } + + template < class Dim_tag > + struct get_maximal_dimension + { + static int value(int D) { return D; } + }; + // specialization + template < int D > + struct get_maximal_dimension > + { + static int value(int) { return D; } + }; + +public: + Triangulation_data_structure( int dim=0) /* Concept */ + : dmax_(get_maximal_dimension::value(dim)), dcur_(-2), + vertices_(), full_cells_() + { + CGAL_assertion_msg(dmax_ > 0, "maximal dimension must be positive."); + } + + ~Triangulation_data_structure() + { + clean_dynamic_memory(); + } + + Triangulation_data_structure(const Triangulation_data_structure & tds) + : dmax_(tds.dmax_), dcur_(tds.dcur_), + vertices_(tds.vertices_), full_cells_(tds.full_cells_) + { + typedef std::map V_map; + typedef std::map C_map; + V_map vmap; + C_map cmap; + Vertex_const_iterator vfrom = tds.vertices_begin(); + Vertex_iterator vto = vertices_begin(); + Full_cell_const_iterator cfrom = tds.full_cells_begin(); + Full_cell_iterator cto = full_cells_begin(); + while( vfrom != tds.vertices_end() ) + vmap[vfrom++] = vto++; + while( cfrom != tds.full_cells_end() ) + cmap[cfrom++] = cto++; + cto = full_cells_begin(); + while( cto != full_cells_end() ) + { + for( int i = 0; i <= (std::max)(0, current_dimension()); ++i ) + { + associate_vertex_with_full_cell(cto, i, vmap[cto->vertex(i)]); + cto->set_neighbor(i, cmap[cto->neighbor(i)]); + } + ++cto; + } + } + + // QUERIES + +protected: + + bool check_range(int i) const + { + if( current_dimension() < 0 ) + { + return (0 == i); + } + return ( (0 <= i) && (i <= current_dimension()) ); + } + +public: + + /* returns the current dimension of the full cells in the triangulation. */ + int maximal_dimension() const { return dmax_; } /* Concept */ + int current_dimension() const { return dcur_; } /* Concept */ + + size_type number_of_vertices() const /* Concept */ + { + return this->vertices_.size(); + } + size_type number_of_full_cells() const /* Concept */ + { + return this->full_cells_.size(); + } + + bool empty() const /* Concept */ + { + return current_dimension() == -2; + } + + Vertex_container & vertices() { return vertices_; } + const Vertex_container & vertices() const { return vertices_; } + Full_cell_container & full_cells() { return full_cells_; } + const Full_cell_container & full_cells() const { return full_cells_; } + + Vertex_handle vertex(Full_cell_handle s, int i) const /* Concept */ + { + CGAL_precondition(s != Full_cell_handle() && check_range(i)); + return s->vertex(i); + } + + Vertex_const_handle vertex(Full_cell_const_handle s, int i) const /* Concept */ + { + CGAL_precondition(s != Full_cell_handle() && check_range(i)); + return s->vertex(i); + } + + bool is_vertex(Vertex_const_handle v) const /* Concept */ + { + if( Vertex_const_handle() == v ) + return false; + Vertex_const_iterator vit = vertices_begin(); + while( vit != vertices_end() && ( v != vit ) ) + ++vit; + return v == vit; + } + + bool is_full_cell(Full_cell_const_handle s) const /* Concept */ + { + if( Full_cell_const_handle() == s ) + return false; + Full_cell_const_iterator sit = full_cells_begin(); + while( sit != full_cells_end() && ( s != sit ) ) + ++sit; + return s == sit; + } + + Full_cell_handle full_cell(Vertex_handle v) const /* Concept */ + { + CGAL_precondition(v != Vertex_handle()); + return v->full_cell(); + } + + Full_cell_const_handle full_cell(Vertex_const_handle v) const /* Concept */ + { + CGAL_precondition(Vertex_const_handle() != v); + return v->full_cell(); + } + + Full_cell_handle neighbor(Full_cell_handle s, int i) const /* Concept */ + { + CGAL_precondition(Full_cell_handle() != s && check_range(i)); + return s->neighbor(i); + } + + Full_cell_const_handle neighbor(Full_cell_const_handle s, int i) const/* Concept */ + { + CGAL_precondition(Full_cell_const_handle() != s && check_range(i)); + return s->neighbor(i); + } + + int mirror_index(Full_cell_handle s, int i) const /* Concept */ + { + CGAL_precondition(Full_cell_handle() != s && check_range(i)); + return s->mirror_index(i); + } + + int mirror_index(Full_cell_const_handle s, int i) const + { + CGAL_precondition(Full_cell_const_handle() != s && check_range(i)); /* Concept */ + return s->mirror_index(i); + } + + int mirror_vertex(Full_cell_handle s, int i) const /* Concept */ + { + CGAL_precondition(Full_cell_handle() != s && check_range(i)); + return s->mirror_vertex(i); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FACETS OPERATIONS + + // works for Face_ = Facet and Face_ = Rotor. + // NOT DOCUMENTED for the Rotor case... + template< typename Face_ > + Full_cell_handle full_cell(const Face_ & f) const /* Concept */ + { + return f.full_cell(); + } + + // works for Face_ = Facet and Face_ = Rotor. + // NOT DOCUMENTED for the Rotor case... + template< class Face_ > + int index_of_covertex(const Face_ & f) const /* Concept */ + { + return f.index_of_covertex(); + } + + // NOT DOCUMENTED + // A Rotor has two covertices + int index_of_second_covertex(const Rotor & f) const + { + return f.index_of_second_covertex(); + } + + // works for Face_ = Facet and Face_ = Rotor. + // NOT DOCUMENTED... + template< class Face_ > + bool is_boundary_facet(const Face_ & f) const + { + if( get_visited(neighbor(full_cell(f), index_of_covertex(f))) ) + return false; + if( ! get_visited(full_cell(f)) ) + return false; + return true; + } + + // NOT DOCUMENTED... + Rotor rotate_rotor(Rotor & f) + { + int opposite = mirror_index(full_cell(f), index_of_covertex(f)); + Full_cell_handle s = neighbor(full_cell(f), index_of_covertex(f)); + int new_second = s->index(vertex(full_cell(f), index_of_second_covertex(f))); + return Rotor(s, new_second, opposite); + } + + // NICE UPDATE OPERATIONS + +protected: + void do_insert_increase_dimension(Vertex_handle, Vertex_handle); +public: +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + + Vertex_handle collapse_face(const Face &); /* Concept */ + void remove_decrease_dimension(Vertex_handle, Vertex_handle); /* Concept */ + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERTIONS + + Vertex_handle insert_in_full_cell(Full_cell_handle); /* Concept */ + Vertex_handle insert_in_face(const Face &); /* Concept */ + Vertex_handle insert_in_facet(const Facet &); /* Concept */ + template< typename Forward_iterator > + Vertex_handle insert_in_hole(Forward_iterator, Forward_iterator, Facet); /* Concept */ + template< typename Forward_iterator, typename OutputIterator > + Vertex_handle insert_in_hole(Forward_iterator, Forward_iterator, Facet, OutputIterator); /* Concept */ + + template< typename OutputIterator > + Full_cell_handle insert_in_tagged_hole(Vertex_handle, Facet, OutputIterator); + + Vertex_handle insert_increase_dimension(Vertex_handle=Vertex_handle()); /* Concept */ + +private: + + // Used by insert_in_tagged_hole + struct IITH_task + { + IITH_task( + Facet boundary_facet_, + int index_of_inside_cell_in_outside_cell_, + Full_cell_handle future_neighbor_ = Full_cell_handle(), + int new_cell_index_in_future_neighbor_ = -1, + int index_of_future_neighbor_in_new_cell_ = -1) + : boundary_facet(boundary_facet_), + index_of_inside_cell_in_outside_cell(index_of_inside_cell_in_outside_cell_), + future_neighbor(future_neighbor_), + new_cell_index_in_future_neighbor(new_cell_index_in_future_neighbor_), + index_of_future_neighbor_in_new_cell(index_of_future_neighbor_in_new_cell_) + {} + + // "new_cell" is the cell about to be created + Facet boundary_facet; + int index_of_inside_cell_in_outside_cell; + Full_cell_handle future_neighbor; + int new_cell_index_in_future_neighbor; + int index_of_future_neighbor_in_new_cell; + }; + + // NOT DOCUMENTED + void clear_visited_marks(Full_cell_handle) const; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DANGEROUS UPDATE OPERATIONS + +private: + + // NOT DOCUMENTED + template< typename FCH > // FCH = Full_cell_[const_]handle + bool get_visited(FCH c) const + { + return c->tds_data().is_visited(); + } + + // NOT DOCUMENTED + template< typename FCH > // FCH = Full_cell_[const_]handle + void set_visited(FCH c, bool m) const + { + if( m ) + c->tds_data().mark_visited(); + else + c->tds_data().clear_visited(); + } + +public: + + void clear() /* Concept */ + { + clean_dynamic_memory(); + dcur_ = -2; + } + + void set_current_dimension(int d) /* Concept */ + { + CGAL_precondition(-2<=d && d<=maximal_dimension()); + dcur_ = d; + } + + Full_cell_handle new_full_cell(Full_cell_handle s) + { + return full_cells_.emplace(*s); + } + + Full_cell_handle new_full_cell() /* Concept */ + { + return full_cells_.emplace(dmax_); + } + + void delete_full_cell(Full_cell_handle s) /* Concept */ + { + CGAL_precondition(Full_cell_handle() != s); + // CGAL_expensive_precondition(is_full_cell(s)); + full_cells_.erase(s); + } + + template< typename Forward_iterator > + void delete_full_cells(Forward_iterator start, Forward_iterator end) /* Concept */ + { + Forward_iterator s = start; + while( s != end ) + full_cells_.erase(*s++); + } + + template< class T > + Vertex_handle new_vertex( const T & t ) + { + return vertices_.emplace(t); + } + + Vertex_handle new_vertex() /* Concept */ + { + return vertices_.emplace(); + } + + void delete_vertex(Vertex_handle v) /* Concept */ + { + CGAL_precondition( Vertex_handle() != v ); + vertices_.erase(v); + } + + void associate_vertex_with_full_cell(Full_cell_handle s, int i, Vertex_handle v) /* Concept */ + { + CGAL_precondition(check_range(i)); + CGAL_precondition(s != Full_cell_handle()); + CGAL_precondition(v != Vertex_handle()); + s->set_vertex(i, v); + v->set_full_cell(s); + } + + void set_neighbors(Full_cell_handle s, int i, Full_cell_handle s1, int j) /* Concept */ + { + CGAL_precondition(check_range(i)); + CGAL_precondition(check_range(j)); + CGAL_precondition(s != Full_cell_handle()); + CGAL_precondition(s1 != Full_cell_handle()); + s->set_neighbor(i, s1); + s1->set_neighbor(j, s); + s->set_mirror_index(i, j); + s1->set_mirror_index(j, i); + } + + // SANITY CHECKS + + bool is_valid(bool = true, int = 0) const; /* Concept */ + + // NOT DOCUMENTED + template< class OutStream> void write_graph(OutStream &); + + Vertex_iterator vertices_begin() { return vertices_.begin(); } /* Concept */ + Vertex_iterator vertices_end() { return vertices_.end(); } /* Concept */ + Full_cell_iterator full_cells_begin() { return full_cells_.begin(); } /* Concept */ + Full_cell_iterator full_cells_end() { return full_cells_.end(); } /* Concept */ + + Vertex_const_iterator vertices_begin() const { return vertices_.begin(); } /* Concept */ + Vertex_const_iterator vertices_end() const { return vertices_.end(); } /* Concept */ + Full_cell_const_iterator full_cells_begin() const { return full_cells_.begin(); } /* Concept */ + Full_cell_const_iterator full_cells_end() const { return full_cells_.end(); } /* Concept */ + + Facet_iterator facets_begin() /* Concept */ + { + if( current_dimension() <= 0 ) + return facets_end(); + return Facet_iterator(*this); + } + Facet_iterator facets_end() /* Concept */ + { + return Facet_iterator(*this, 0); + } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - FULL CELL GATHERING + + // a traversal predicate for gathering full_cells incident to a given face + // ``incident'' means that the given face is a subface of the full_cell + class Incident_full_cell_traversal_predicate + { + const Face & f_; + int dim_; + const Triangulation_data_structure & tds_; + public: + Incident_full_cell_traversal_predicate(const Triangulation_data_structure & tds, + const Face & f) + : f_(f), tds_(tds) + { + dim_ = f.face_dimension(); + } + bool operator()(const Facet & facet) const + { + Vertex_handle v = tds_.full_cell(facet)->vertex(tds_.index_of_covertex(facet)); + for( int i = 0; i <= dim_; ++i ) + { + if( v == f_.vertex(i) ) + return false; + } + return true; + } + }; + + // a traversal predicate for gathering full_cells having a given face as subface + class Star_traversal_predicate + { + const Face & f_; + int dim_; + const Triangulation_data_structure & tds_; + public: + Star_traversal_predicate(const Triangulation_data_structure & tds, + const Face & f) + : f_(f), tds_(tds) + { + dim_ = f.face_dimension(); + } + bool operator()(const Facet & facet) const + { + Full_cell_handle s = tds_.full_cell(facet)->neighbor(tds_.index_of_covertex(facet)); + for( int j = 0; j <= tds_.current_dimension(); ++j ) + { + for( int i = 0; i <= dim_; ++i ) + if( s->vertex(j) == f_.vertex(i) ) + return true; + } + return false; + } + }; + + template< typename TraversalPredicate, typename OutputIterator > + Facet gather_full_cells(Full_cell_handle, TraversalPredicate &, OutputIterator &) const; /* Concept */ + template< typename OutputIterator > + OutputIterator incident_full_cells(const Face &, OutputIterator) const; /* Concept */ + template< typename OutputIterator > + OutputIterator incident_full_cells(Vertex_const_handle, OutputIterator) const; /* Concept */ + template< typename OutputIterator > + OutputIterator star(const Face &, OutputIterator) const; /* Concept */ +#ifndef CGAL_CFG_NO_CPP0X_DEFAULT_TEMPLATE_ARGUMENTS_FOR_FUNCTION_TEMPLATES + template< typename OutputIterator, typename Comparator = std::less > + OutputIterator incident_upper_faces(Vertex_const_handle v, int dim, OutputIterator out, Comparator cmp = Comparator()) + { + return incident_faces(v, dim, out, cmp, true); + } + template< typename OutputIterator, typename Comparator = std::less > + OutputIterator incident_faces(Vertex_const_handle, int, OutputIterator, Comparator = Comparator(), bool = false) const; +#else + template< typename OutputIterator, typename Comparator > + OutputIterator incident_upper_faces(Vertex_const_handle v, int dim, OutputIterator out, Comparator cmp = Comparator()) + { + return incident_faces(v, dim, out, cmp, true); + } + template< typename OutputIterator > + OutputIterator incident_upper_faces(Vertex_const_handle v, int dim, OutputIterator out) + { + return incident_faces(v, dim, out, std::less(), true); + } + template< typename OutputIterator, typename Comparator > + OutputIterator incident_faces(Vertex_const_handle, int, OutputIterator, Comparator = Comparator(), bool = false) const; + template< typename OutputIterator > + OutputIterator incident_faces(Vertex_const_handle, int, OutputIterator, + std::less = std::less(), bool = false) const; +#endif + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INPUT / OUTPUT + + std::istream & read_full_cells(std::istream &, const std::vector &); + std::ostream & write_full_cells(std::ostream &, std::map &) const; + +}; // end of ``declaration/definition'' of Triangulation_data_structure<...> + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +// FUNCTIONS THAT ARE MEMBER FUNCTIONS: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - THE GATHERING METHODS + +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator > +OutputIterator +Triangulation_data_structure +::incident_full_cells(const Face & f, OutputIterator out) const /* Concept */ +{ + // CGAL_expensive_precondition_msg(is_full_cell(f.full_cell()), "the facet does not belong to the Triangulation"); + Incident_full_cell_traversal_predicate tp(*this, f); + gather_full_cells(f.full_cell(), tp, out); + return out; +} + +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator > +OutputIterator +Triangulation_data_structure +::incident_full_cells(Vertex_const_handle v, OutputIterator out) const /* Concept */ +{ +// CGAL_expensive_precondition(is_vertex(v)); + CGAL_precondition(Vertex_handle() != v); + Face f(v->full_cell()); + f.set_index(0, v->full_cell()->index(v)); + return incident_full_cells(f, out); +} + +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator > +OutputIterator +Triangulation_data_structure +::star(const Face & f, OutputIterator out) const /* Concept */ +{ + // CGAL_precondition_msg(is_full_cell(f.full_cell()), "the facet does not belong to the Triangulation"); + Star_traversal_predicate tp(*this, f); + gather_full_cells(f.full_cell(), tp, out); + return out; +} + +template< class Dim, class Vb, class Fcb > +template< typename TraversalPredicate, typename OutputIterator > +typename Triangulation_data_structure::Facet +Triangulation_data_structure +::gather_full_cells(Full_cell_handle start, + TraversalPredicate & tp, + OutputIterator & out) const /* Concept */ +{ + std::queue queue; + set_visited(start, true); + queue.push(start); + const int cur_dim = current_dimension(); + Facet ft; + while( ! queue.empty() ) + { + Full_cell_handle s = queue.front(); + queue.pop(); + *out = s; + ++out; + for( int i = 0; i <= cur_dim; ++i ) + { + Full_cell_handle n = s->neighbor(i); + if( ! get_visited(n) ) + { + set_visited(n, true); + if( tp(Facet(s, i)) ) + queue.push(n); + else + ft = Facet(s, i); + } + } + } + clear_visited_marks(start); + return ft; +} + +#ifdef CGAL_CFG_NO_CPP0X_DEFAULT_TEMPLATE_ARGUMENTS_FOR_FUNCTION_TEMPLATES +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator > +OutputIterator +Triangulation_data_structure +::incident_faces(Vertex_const_handle v, int dim, OutputIterator out, + std::less cmp, bool upper_faces) const +{ + return incident_faces >(v, dim, out, cmp, upper_faces); +} +#endif + +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator, typename Comparator > +OutputIterator +Triangulation_data_structure +::incident_faces(Vertex_const_handle v, int dim, OutputIterator out, Comparator cmp, bool upper_faces) const +{ + CGAL_precondition( 0 < dim ); + if( dim >= current_dimension() ) + return out; + typedef std::vector Simplices; + Simplices simps; + simps.reserve(64); + // gather incident full_cells + std::back_insert_iterator sout(simps); + incident_full_cells(v, sout); + // for storing the handles to the vertices of a full_cell + typedef std::vector Vertices; + typedef std::vector Indices; + Vertices vertices(1 + current_dimension()); + Indices sorted_idx(1 + current_dimension()); + // setup Face comparator and Face_set + typedef internal::Triangulation::Compare_faces_with_common_first_vertex + Upper_face_comparator; + Upper_face_comparator ufc(dim); + typedef std::set Face_set; + Face_set face_set(ufc); + for( typename Simplices::const_iterator s = simps.begin(); s != simps.end(); ++s ) + { + int v_idx(0); // the index of |v| in the sorted full_cell + // get the vertices of the full_cell and sort them + for( int i = 0; i <= current_dimension(); ++i ) + vertices[i] = (*s)->vertex(i); + if( upper_faces ) + { + std::sort(vertices.begin(), vertices.end(), cmp); + while( vertices[v_idx] != v ) + ++v_idx; + } + else + { + while( vertices[v_idx] != v ) + ++v_idx; + if( 0 != v_idx ) + std::swap(vertices[0], vertices[v_idx]); + v_idx = 0; + typename Vertices::iterator vbegin(vertices.begin()); + ++vbegin; + std::sort(vbegin, vertices.end(), cmp); + } + if( v_idx + dim > current_dimension() ) + continue; // |v| is too far to the right + // stores the index of the vertices of s in the same order + // as in |vertices|: + for( int i = 0; i <= current_dimension(); ++i ) + sorted_idx[i] = (*s)->index(vertices[i]); + // init state for enumerating all candidate faces: + internal::Combination_enumerator f_idx(dim, v_idx + 1, current_dimension()); + Face f(*s); + f.set_index(0, sorted_idx[v_idx]); + while( ! f_idx.end() ) + { + for( int i = 0; i < dim; ++i ) + f.set_index(1 + i, sorted_idx[f_idx[i]]); + face_set.insert(f); // checks if face has already been found + + // compute next sorted face (lexicographic enumeration) + ++f_idx; + } + } + typename Face_set::iterator fit = face_set.begin(); + while( fit != face_set.end() ) + *out++ = *fit++; + return out; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - THE REMOVAL METHODS + +template +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::collapse_face(const Face & f) /* Concept */ +{ + const int fd = f.face_dimension(); + CGAL_precondition( (1 <= fd ) && (fd < current_dimension())); + std::vector simps; + // save the Face's vertices: + Full_cell s; + for( int i = 0; i <= fd; ++i ) + s.set_vertex(i, f.vertex(i)); + // compute the star of f + simps.reserve(64); + std::back_insert_iterator > out(simps); + star(f, out); + Vertex_handle v = insert_in_hole(simps.begin(), simps.end(), Facet(f.full_cell(), f.index(0))); + for( int i = 0; i <= fd; ++i ) + delete_vertex(s.vertex(i)); + return v; +} + +template +void +Triangulation_data_structure +::remove_decrease_dimension(Vertex_handle v, Vertex_handle star) /* Concept */ +{ + CGAL_assertion( current_dimension() >= -1 ); + if( -1 == current_dimension() ) + { + clear(); + return; + } + else if( 0 == current_dimension() ) + { + delete_full_cell(v->full_cell()); + delete_vertex(v); + star->full_cell()->set_neighbor(0, Full_cell_handle()); + set_current_dimension(-1); + return; + } + else if( 1 == current_dimension() ) + { + Full_cell_handle s = v->full_cell(); + int star_index; + if( s->has_vertex(star, star_index) ) + s = s->neighbor(star_index); + // Here, |star| is not a vertex of |s|, so it's the only finite + // full_cell + Full_cell_handle inf1 = s->neighbor(0); + Full_cell_handle inf2 = s->neighbor(1); + Vertex_handle v2 = s->vertex(1 - s->index(v)); + delete_vertex(v); + delete_full_cell(s); + inf1->set_vertex(1, Vertex_handle()); + inf1->set_vertex(1, Vertex_handle()); + inf2->set_neighbor(1, Full_cell_handle()); + inf2->set_neighbor(1, Full_cell_handle()); + associate_vertex_with_full_cell(inf1, 0, star); + associate_vertex_with_full_cell(inf2, 0, v2); + set_neighbors(inf1, 0, inf2, 0); + set_current_dimension(0); + return; + } + typedef std::vector Simplices; + Simplices simps; + incident_full_cells(v, std::back_inserter(simps)); + for( typename Simplices::iterator it = simps.begin(); it != simps.end(); ++it ) + { + int v_idx = (*it)->index(v); + if( ! (*it)->has_vertex(star) ) + { + delete_full_cell((*it)->neighbor(v_idx)); + for( int i = 0; i <= current_dimension(); ++i ) + (*it)->vertex(i)->set_full_cell(*it); + } + else + star->set_full_cell(*it); + if( v_idx != current_dimension() ) + { + (*it)->swap_vertices(v_idx, current_dimension()); + (*it)->swap_vertices(current_dimension() - 2, current_dimension() - 1); + } + (*it)->set_vertex(current_dimension(), Vertex_handle()); + (*it)->set_neighbor(current_dimension(), Full_cell_handle()); + } + set_current_dimension(current_dimension()-1); + delete_vertex(v); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - THE INSERTION METHODS + +template +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_in_full_cell(Full_cell_handle s) /* Concept */ +{ + CGAL_precondition(0 < current_dimension()); + CGAL_precondition(Full_cell_handle() != s); + // CGAL_expensive_precondition(is_full_cell(s)); + + const int cur_dim = current_dimension(); + Vertex_handle v = new_vertex(); + // the full_cell 'fc' is just used to store the handle to all the new full_cells. + Full_cell fc(maximal_dimension()); + for( int i = 1; i <= cur_dim; ++i ) + { + Full_cell_handle new_s = new_full_cell(s); + fc.set_neighbor(i, new_s); + associate_vertex_with_full_cell(new_s, i, v); + s->vertex(i-1)->set_full_cell(new_s); + set_neighbors(new_s, i, neighbor(s, i), mirror_index(s, i)); + } + fc.set_neighbor(0, s); + associate_vertex_with_full_cell(s, 0, v); + for( int i = 0; i <= cur_dim; ++i ) + for( int j = 0; j <= cur_dim; ++j ) + { + if( j == i ) continue; + set_neighbors(fc.neighbor(i), j, fc.neighbor(j), i); + } + return v; +} + +template +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_in_face(const Face & f) /* Concept */ +{ + std::vector simps; + simps.reserve(64); + std::back_insert_iterator > out(simps); + incident_full_cells(f, out); + return insert_in_hole(simps.begin(), simps.end(), Facet(f.full_cell(), f.index(0))); +} +template +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_in_facet(const Facet & ft) /* Concept */ +{ + Full_cell_handle s[2]; + s[0] = full_cell(ft); + int i = index_of_covertex(ft); + s[1] = s[0]->neighbor(i); + i = ( i + 1 ) % current_dimension(); + return insert_in_hole(s, s+2, Facet(s[0], i)); +} + +template +template < typename OutputIterator > +typename Triangulation_data_structure::Full_cell_handle +Triangulation_data_structure +::insert_in_tagged_hole(Vertex_handle v, Facet f, + OutputIterator new_full_cells) +{ + CGAL_assertion_msg(is_boundary_facet(f), "starting facet should be on the hole boundary"); + + const int cur_dim = current_dimension(); + Full_cell_handle new_s; + + std::queue task_queue; + task_queue.push( + IITH_task(f, mirror_index(full_cell(f), index_of_covertex(f))) ); + + while (!task_queue.empty()) + { + IITH_task task = task_queue.front(); + task_queue.pop(); + + Full_cell_handle old_s = full_cell(task.boundary_facet); + const int facet_index = index_of_covertex(task.boundary_facet); + + Full_cell_handle outside_neighbor = neighbor(old_s, facet_index); + // Here, "new_s" might actually be a new cell, but it might also be "old_s" + // if it has not been treated already in the meantime + new_s = neighbor(outside_neighbor, task.index_of_inside_cell_in_outside_cell); + // If the cell has not been treated yet + if (old_s == new_s) + { + new_s = new_full_cell(); + + int i(0); + for ( ; i < facet_index ; ++i) + associate_vertex_with_full_cell(new_s, i, old_s->vertex(i)); + ++i; // skip facet_index + for ( ; i <= cur_dim ; ++i) + associate_vertex_with_full_cell(new_s, i, old_s->vertex(i)); + associate_vertex_with_full_cell(new_s, facet_index, v); + set_neighbors(new_s, + facet_index, + outside_neighbor, + mirror_index(old_s, facet_index)); + + // add the new full_cell to the list of new full_cells + *new_full_cells++ = new_s; + + // check all of |Facet f|'s neighbors + for (i = 0 ; i <= cur_dim ; ++i) + { + if (facet_index == i) + continue; + // we define a |Rotor| because it makes it easy to rotate around + // in a self contained fashion. The corresponding potential + // boundary facet is Facet(full_cell(rot), index_of_covertex(rot)) + Rotor rot(old_s, i, facet_index); + // |rot| on line above, stands for Candidate Facet + while (!is_boundary_facet(rot)) + rot = rotate_rotor(rot); + + // we did find the |i|-th neighbor of Facet(old_s, facet_index)... + // has it already been extruded to center point |v| ? + Full_cell_handle inside = full_cell(rot); + Full_cell_handle outside = neighbor(inside, index_of_covertex(rot)); + // "m" is the vertex of outside which is not on the boundary + Vertex_handle m = inside->mirror_vertex(index_of_covertex(rot), current_dimension()); // CJTODO: use mirror_index? + // "index" is the index of m in "outside" + int index = outside->index(m); + // new_neighbor is the inside cell which is registered as the neighbor + // of the outside cell => it's either a newly created inside cell or an + // old inside cell which we are about to delete + Full_cell_handle new_neighbor = outside->neighbor(index); + + // Is new_neighbor still the old neighbor? + if (new_neighbor == inside) + { + task_queue.push(IITH_task( + Facet(inside, index_of_covertex(rot)), // boundary facet + index, // index_of_inside_cell_in_outside_cell + new_s, // future_neighbor + i, // new_cell_index_in_future_neighbor + index_of_second_covertex(rot) // index_of_future_neighbor_in_new_cell + )); + } + } + } + + // If there is some neighbor stories to fix + if (task.future_neighbor != Full_cell_handle()) + { + // now the new neighboring full_cell exists, we link both + set_neighbors(new_s, + task.index_of_future_neighbor_in_new_cell, + task.future_neighbor, + task.new_cell_index_in_future_neighbor); + } + } + + return new_s; +} + +template< class Dim, class Vb, class Fcb > +template< typename Forward_iterator, typename OutputIterator > +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_in_hole(Forward_iterator start, Forward_iterator end, Facet f, + OutputIterator out) /* Concept */ +{ + CGAL_expensive_precondition( + ( std::distance(start, end) == 1 ) + || ( current_dimension() > 1 ) ); + Forward_iterator sit = start; + while( end != sit ) + set_visited(*sit++, true); + Vertex_handle v = new_vertex(); + insert_in_tagged_hole(v, f, out); + delete_full_cells(start, end); + return v; +} + +template< class Dim, class Vb, class Fcb > +template< typename Forward_iterator > +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_in_hole(Forward_iterator start, Forward_iterator end, Facet f) /* Concept */ +{ + Emptyset_iterator out; + return insert_in_hole(start, end, f, out); +} + +template +void +Triangulation_data_structure +::clear_visited_marks(Full_cell_handle start) const // NOT DOCUMENTED +{ + CGAL_precondition(start != Full_cell_handle()); + + std::queue queue; + set_visited(start, false); + queue.push(start); + const int cur_dim = current_dimension(); + while( ! queue.empty() ) + { + Full_cell_handle s = queue.front(); + queue.pop(); + for( int i = 0; i <= cur_dim; ++i ) + { + if( get_visited(s->neighbor(i)) ) + { + set_visited(s->neighbor(i), false); + queue.push(s->neighbor(i)); + } + } + } +} + +template +void Triangulation_data_structure +::do_insert_increase_dimension(Vertex_handle x, Vertex_handle star) +{ + Full_cell_handle start = full_cells_begin(); + Full_cell_handle swap_me; + const int cur_dim = current_dimension(); + for( Full_cell_iterator S = full_cells_begin(); S != full_cells_end(); ++S ) + { + if( Vertex_handle() != S->vertex(cur_dim) ) + continue; + set_visited(S, true); + // extends full_cell |S| to include the new vertex as the + // current_dimension()-th vertex + associate_vertex_with_full_cell(S, cur_dim, x); + if( ! S->has_vertex(star) ) + { // S is bounded, we create its unbounded "twin" full_cell + Full_cell_handle S_new = new_full_cell(); + set_neighbors(S, cur_dim, S_new, 0); + associate_vertex_with_full_cell(S_new, 0, star); + // here, we could be clever so as to get consistent orientation + for( int k = 1; k <= cur_dim; ++k ) + associate_vertex_with_full_cell(S_new, k, vertex(S, k - 1)); + } + } + // now we setup the neighbors + set_visited(start, false); + std::queue queue; + queue.push(start); + while( ! queue.empty() ) + { + Full_cell_handle S = queue.front(); + queue.pop(); + // here, the first visit above ensured that all neighbors exist now. + // Now we need to connect them with adjacency relation + int star_index; + if( S->has_vertex(star, star_index) ) + { + set_neighbors( S, cur_dim, neighbor(neighbor(S, star_index), cur_dim), + // this is tricky :-) : + mirror_index(S, star_index) + 1); + } + else + { + Full_cell_handle S_new = neighbor(S, cur_dim); + for( int k = 0 ; k < cur_dim ; ++k ) + { + Full_cell_handle S_opp = neighbor(S, k); + if( ! S_opp->has_vertex(star) ) + set_neighbors(S_new, k + 1, neighbor(S_opp, cur_dim), mirror_index(S, k) + 1); + // neighbor of S_new opposite to v is S_new' + // the vertex opposite to v remains the same but ... + // remember the shifting of the vertices one step to the right + } + } + for( int k = 0 ; k < cur_dim ; ++k ) + if( get_visited(neighbor(S, k)) ) + { + set_visited(neighbor(S, k), false); + queue.push(neighbor(S, k)); + } + } + if( ( ( cur_dim % 2 ) == 0 ) && ( cur_dim > 1 ) ) + { + for( Full_cell_iterator S = full_cells_begin(); S != full_cells_end(); ++S ) + { + if( x != S->vertex(cur_dim) ) + S->swap_vertices(cur_dim - 1, cur_dim); + } + } + if( Full_cell_handle() != swap_me ) + swap_me->swap_vertices(1, 2); +} + +template +typename Triangulation_data_structure::Vertex_handle +Triangulation_data_structure +::insert_increase_dimension(Vertex_handle star) /* Concept */ +{ + const int prev_cur_dim = current_dimension(); + CGAL_precondition(prev_cur_dim < maximal_dimension()); + if( -2 != current_dimension() ) + { + CGAL_precondition( Vertex_handle() != star ); + CGAL_expensive_precondition(is_vertex(star)); + } + + set_current_dimension(prev_cur_dim + 1); + Vertex_handle v = new_vertex(); + switch( prev_cur_dim ) + { + case -2: + { // insertion of the first vertex + // ( geometrically : infinite vertex ) + Full_cell_handle s = new_full_cell(); + associate_vertex_with_full_cell(s, 0, v); + break; + } + case -1: + { // insertion of the second vertex + // ( geometrically : first finite vertex ) + //we create a triangulation of the 0-sphere, with + // vertices |star| and |v| + Full_cell_handle infinite_full_cell = star->full_cell(); + Full_cell_handle finite_full_cell = new_full_cell(); + associate_vertex_with_full_cell(finite_full_cell, 0, v); + set_neighbors(infinite_full_cell, 0, finite_full_cell, 0); + break; + } + default: + do_insert_increase_dimension(v, star); + break; + } + return v; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - VALIDITY CHECKS + +template +bool Triangulation_data_structure +::is_valid(bool verbose, int /* level */) const /* Concept */ +{ + Full_cell_const_handle s, t; + Vertex_const_handle v; + int i, j, k; + + if( current_dimension() == -2 ) + { + if( ! vertices_.empty() || ! full_cells_.empty() ) + { + if( verbose ) CGAL_warning_msg(false, "current dimension is -2 but there are vertices or full_cells"); + return false; + } + } + + if( current_dimension() == -1 ) + { + if ( (number_of_vertices() != 1) || (number_of_full_cells() != 1) ) + { + if( verbose ) CGAL_warning_msg(false, "current dimension is -1 but there isn't one vertex and one full_cell"); + return false; + } + } + + for( v = vertices_begin(); v != vertices_end(); ++v ) + { + if( ! v->is_valid(verbose) ) + return false; + } + + // FUTURE: for each vertex v, gather incident full_cells. then, check that + // any full_cell containing v is among those gathered full_cells... + + if( current_dimension() < 0 ) + return true; + + for( s = full_cells_begin(); s != full_cells_end(); ++s ) + { + if( ! s->is_valid(verbose) ) + return false; + // check that the full cell has no duplicate vertices + for( i = 0; i <= current_dimension(); ++i ) + for( j = i + 1; j <= current_dimension(); ++j ) + if( vertex(s,i) == vertex(s,j) ) + { + CGAL_warning_msg(false, "a full_cell has two equal vertices"); + return false; + } + } + + for( s = full_cells_begin(); s != full_cells_end(); ++s ) + { + for( i = 0; i <= current_dimension(); ++i ) + if( (t = neighbor(s,i)) != Full_cell_const_handle() ) + { + int l = mirror_index(s,i); + if( s != neighbor(t,l) || i != mirror_index(t,l) ) + { + if( verbose ) CGAL_warning_msg(false, "neighbor relation is not symmetric"); + return false; + } + for( j = 0; j <= current_dimension(); ++j ) + if( j != i ) + { + // j must also occur as a vertex of t + for( k = 0; k <= current_dimension() && ( vertex(s,j) != vertex(t,k) || k == l); ++k ) + ; + if( k > current_dimension() ) + { + if( verbose ) CGAL_warning_msg(false, "too few shared vertices between neighbors full_cells."); + return false; + } + } + } + else + { + if( verbose ) CGAL_warning_msg(false, "full_cell has a NULL neighbor"); + return false; + } + } + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - INPUT / OUTPUT + +// NOT DOCUMENTED +template +template +void Triangulation_data_structure +::write_graph(OutStream & os) +{ + std::vector > edges; + os << number_of_vertices() + 1; // add the vertex at infinity + int count(1); + for( Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit ) + vit->idx_ = count++; + edges.resize(number_of_vertices()+1); + for( Full_cell_iterator sit = full_cells_begin(); sit != full_cells_end(); ++sit ) + { + int v1 = 0; + while( v1 < current_dimension() ) + { + int v2 = v1 + 1; + while( v2 <= current_dimension() ) + { + int i1, i2; + if( Vertex_handle() != sit-> vertex(v1) ) + i1 = sit->vertex(v1)->idx_; + else + i1 = 0; + if( Vertex_handle() != sit-> vertex(v2) ) + i2 = sit->vertex(v2)->idx_; + else + i2 = 0; + edges[i1].insert(i2); + edges[i2].insert(i1); + ++v2; + } + ++v1; + } + } + for( std::size_t i = 0; i < edges.size(); ++i ) + { + os << std::endl << edges[i].size(); + for( std::set::const_iterator nit = edges[i].begin(); + nit != edges[i].end(); ++nit ) + { + os << ' ' << (*nit); + } + } +} + +// NOT DOCUMENTED... +template +std::istream & +Triangulation_data_structure +::read_full_cells(std::istream & is, const std::vector & vertices) +{ + std::size_t m; // number of full_cells + int index; + const int cd = current_dimension(); + if( is_ascii(is) ) + is >> m; + else + read(is, m, io_Read_write()); + + std::vector full_cells; + full_cells.reserve(m); + // read the vertices of each full_cell + std::size_t i = 0; + while( i < m ) + { + Full_cell_handle s = new_full_cell(); + full_cells.push_back(s); + for( int j = 0; j <= cd; ++j ) + { + if( is_ascii(is) ) + is >> index; + else + read(is, index); + s->set_vertex(j, vertices[index]); + } + // read other non-combinatorial information for the full_cells + is >> (*s); + ++i; + } + + // read the neighbors of each full_cell + i = 0; + if( is_ascii(is) ) + while( i < m ) + { + for( int j = 0; j <= cd; ++j ) + { + is >> index; + full_cells[i]->set_neighbor(j, full_cells[index]); + } + ++i; + } + else + while( i < m ) + { + for( int j = 0; j <= cd; ++j ) + { + read(is, index); + full_cells[i]->set_neighbor(j, full_cells[index]); + } + ++i; + } + + // compute the mirror indices + for( i = 0; i < m; ++i ) + { + Full_cell_handle s = full_cells[i]; + for( int j = 0; j <= cd; ++j ) + { + if( -1 != s->mirror_index(j) ) + continue; + Full_cell_handle n = s->neighbor(j); + int k = 0; + Full_cell_handle nn = n->neighbor(k); + while( s != nn ) + nn = n->neighbor(++k); + s->set_mirror_index(j,k); + n->set_mirror_index(k,j); + } + } + return is; +} + +// NOT DOCUMENTED... +template +std::ostream & +Triangulation_data_structure +::write_full_cells(std::ostream & os, std::map & index_of_vertex) const +{ + std::map index_of_full_cell; + + std::size_t m = number_of_full_cells(); + + if( is_ascii(os) ) + os << std::endl << m; + else + write(os, m, io_Read_write()); + + const int cur_dim = current_dimension(); + // write the vertex indices of each full_cell + int i = 0; + for( Full_cell_const_iterator it = full_cells_begin(); it != full_cells_end(); ++it ) + { + index_of_full_cell[it] = i++; + if( is_ascii(os) ) + os << std::endl; + for( int j = 0; j <= cur_dim; ++j ) + { + if( is_ascii(os) ) + os << ' ' << index_of_vertex[it->vertex(j)]; + else + write(os, index_of_vertex[it->vertex(j)]); + } + // write other non-combinatorial information for the full_cells + os << (*it); + } + + CGAL_assertion( (std::size_t) i == m ); + + // write the neighbors of each full_cell + if( is_ascii(os) ) + for( Full_cell_const_iterator it = full_cells_begin(); it != full_cells_end(); ++it ) + { + os << std::endl; + for( int j = 0; j <= cur_dim; ++j ) + os << ' ' << index_of_full_cell[it->neighbor(j)]; + } + else + for( Full_cell_const_iterator it = full_cells_begin(); it != full_cells_end(); ++it ) + { + for( int j = 0; j <= cur_dim; ++j ) + write(os, index_of_full_cell[it->neighbor(j)]); + } + + return os; +} + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS: + +template +std::istream & +operator>>(std::istream & is, Triangulation_data_structure & tr) + // reads : + // - the dimensions (maximal and current) + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of full_cells + // - the full_cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each full_cell + // - the neighbors of each full_cell by their index in the preceding list +{ + typedef Triangulation_data_structure TDS; + typedef typename TDS::Vertex_handle Vertex_handle; + + // read current dimension and number of vertices + std::size_t n; + int cd; + if( is_ascii(is) ) + is >> cd >> n; + else + { + read(is, cd); + read(is, n, io_Read_write()); + } + + CGAL_assertion_msg( cd <= tr.maximal_dimension(), "input Triangulation_data_structure has too high dimension"); + + tr.clear(); + tr.set_current_dimension(cd); + + if( n == 0 ) + return is; + + std::vector vertices; + vertices.resize(n); + + // read the vertices: + std::size_t i(0); + while( i < n ) + { + vertices[i] = tr.new_vertex(); + is >> (*vertices[i]); // read a vertex + ++i; + } + + // now, read the combinatorial information + return tr.read_full_cells(is, vertices); +} + +template +std::ostream & +operator<<(std::ostream & os, const Triangulation_data_structure & tr) + // writes : + // - the dimensions (maximal and current) + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of full cells + // - the full cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each full_cell + // - the neighbors of each full_cell by their index in the preceding list +{ + typedef Triangulation_data_structure TDS; + typedef typename TDS::Vertex_const_handle Vertex_handle; + typedef typename TDS::Vertex_const_iterator Vertex_iterator; + + // outputs dimension and number of vertices + std::size_t n = tr.number_of_vertices(); + if( is_ascii(os) ) + os << tr.current_dimension() << std::endl << n; + else + { + write(os, tr.current_dimension()); + write(os, n, io_Read_write()); + } + + if( n == 0 ) + return os; + + // write the vertices + std::map index_of_vertex; + int i = 0; + for( Vertex_iterator it = tr.vertices_begin(); it != tr.vertices_end(); ++it, ++i ) + { + os << *it; // write the vertex + if (is_ascii(os)) + os << std::endl; + index_of_vertex[it] = i; + } + CGAL_assertion( (std::size_t) i == n ); + + // output the combinatorial information + return tr.write_full_cells(os, index_of_vertex); +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_DATA_STRUCTURE_H diff --git a/include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h b/include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h new file mode 100644 index 00000000..541a6a85 --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h @@ -0,0 +1,311 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_DS_FULL_CELL_H +#define CGAL_TRIANGULATION_DS_FULL_CELL_H + +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +template< class TDS = void, typename FullCellStoragePolicy = Default > +class Triangulation_ds_full_cell +{ + typedef typename Default::Get::type + Storage_policy; + typedef Triangulation_ds_full_cell Self; + typedef typename TDS::Maximal_dimension Maximal_dimension; + +public: + typedef TDS Triangulation_data_structure; + typedef typename TDS::Face Face; + typedef typename TDS::Vertex_handle Vertex_handle; /* Concept */ + typedef typename TDS::Vertex_const_handle Vertex_const_handle; + typedef typename TDS::Full_cell_handle Full_cell_handle; /* Concept */ + typedef typename TDS::Full_cell_const_handle Full_cell_const_handle; + typedef typename TDS::Full_cell_data TDS_data; /* data that the TDS wants to be stored here */ + template< typename TDS2 > + struct Rebind_TDS /* Concept */ + { + typedef Triangulation_ds_full_cell Other; + }; + +private: // STORAGE + typedef TFC_data< Vertex_handle, Full_cell_handle, + Maximal_dimension, Storage_policy > Combinatorics; + friend struct TFC_data< Vertex_handle, Full_cell_handle, + Maximal_dimension, Storage_policy >; + // array of vertices + typedef typename Combinatorics::Vertex_handle_array Vertex_handle_array; + // neighbor simplices + typedef typename Combinatorics::Full_cell_handle_array Full_cell_handle_array; + + // NOT DOCUMENTED... + typename Combinatorics::Xor_type xor_of_vertices(const int cur_dim) const + { + return combinatorics_.xor_of_vertices(cur_dim); + } + +public: + typedef typename Vertex_handle_array::const_iterator Vertex_handle_const_iterator; + typedef Vertex_handle_const_iterator Vertex_handle_iterator; /* Concept */ + + Triangulation_ds_full_cell(const int dmax) /* Concept */ + : combinatorics_(dmax), tds_data_() + { + CGAL_assertion( dmax > 0 ); + for( int i = 0; i <= dmax; ++i ) + { + set_neighbor(i, Full_cell_handle()); + set_vertex(i, Vertex_handle()); + set_mirror_index(i, -1); + } + } + + Triangulation_ds_full_cell(const Triangulation_ds_full_cell & s) /* Concept */ + : combinatorics_(s.combinatorics_), tds_data_(s.tds_data_) + {} + + ~Triangulation_ds_full_cell() {} + + int maximal_dimension() const /* Concept */ + { + return static_cast(vertices().size() - 1); + } + + Vertex_handle_const_iterator vertices_begin() const /* Concept */ + { + return vertices().begin(); + } + + Vertex_handle_const_iterator vertices_end() const /* Concept */ + { + return vertices().end(); + } + + Vertex_handle vertex(const int i) const /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + return vertices()[i]; + } + + Full_cell_handle neighbor(const int i) const /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + return neighbors()[i]; + } + + int mirror_index(const int i) const /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + return combinatorics_.mirror_index(i); + } + + // Advanced... + Vertex_handle mirror_vertex(const int i, const int cur_dim) const /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + return combinatorics_.mirror_vertex(i, cur_dim); + } + + int index(Full_cell_const_handle s) const /* Concept */ + { + // WE ASSUME THE FULL CELL WE ARE LOOKING FOR INDEED EXISTS ! + CGAL_precondition(has_neighbor(s)); + int index(0); + while( neighbor(index) != s ) + ++index; + return index; + } + + int index(Vertex_const_handle v) const /* Concept */ + { + // WE ASSUME THE VERTEX WE ARE LOOKING FOR INDEED EXISTS ! + CGAL_precondition(has_vertex(v)); + int index(0); + while( vertex(index) != v ) + ++index; + return index; + } + + void set_vertex(const int i, Vertex_handle v) /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + vertices()[i] = v; + } + + void set_neighbor(const int i, Full_cell_handle s) /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + neighbors()[i] = s; + } + + void set_mirror_index(const int i, const int index) /* Concept */ + { + CGAL_precondition(0<=i && i<=maximal_dimension()); + combinatorics_.set_mirror_index(i, index); + } + + bool has_vertex(Vertex_const_handle v) const /* Concept */ + { + int index; + return has_vertex(v, index); + } + + bool has_vertex(Vertex_const_handle v, int & index) const /* Concept */ + { + const int d = maximal_dimension(); + index = 0; + while( (index <= d) && (vertex(index) != v) ) + ++index; + return (index <= d); + } + + bool has_neighbor(Full_cell_const_handle s) const /* Concept */ + { + int index; + return has_neighbor(s, index); + } + + bool has_neighbor(Full_cell_const_handle s, int & index) const /* Concept */ + { + const int d = maximal_dimension(); + index = 0; + while( (index <= d) && (neighbor(index) != s) ) + ++index; + return (index <= d); + } + + void swap_vertices(const int d1, const int d2) /* Concept */ + { + CGAL_precondition(0 <= d1 && d1<=maximal_dimension()); + CGAL_precondition(0 <= d2 && d2<=maximal_dimension()); + combinatorics_.swap_vertices(d1, d2); + } + + const TDS_data & tds_data() const { return tds_data_; } /* Concept */ + TDS_data & tds_data() { return tds_data_; } /* Concept */ + + void* for_compact_container() const { return combinatorics_.for_compact_container(); } + void* & for_compact_container() { return combinatorics_.for_compact_container(); } + + bool is_valid(bool verbose = false, int = 0) const /* Concept */ + { + const int d = maximal_dimension(); + int i(0); + // test that the non-null Vertex_handles come first, before all null ones + while( i <= d && vertex(i) != Vertex_handle() ) ++i; + while( i <= d && vertex(i) == Vertex_handle() ) ++i; + if( i <= d ) + { + if( verbose ) CGAL_warning_msg(false, "full cell has garbage handles to vertices."); + return false; + } + for( i = 0; i <= d; ++i ) + { + if( Vertex_handle() == vertex(i) ) + break; // there are no more vertices + Full_cell_handle n(neighbor(i)); + if( Full_cell_handle() != n ) + { + int mirror_idx(mirror_index(i)); + if( n->neighbor(mirror_idx) == Full_cell_handle() ) + { + if( verbose ) CGAL_warning_msg(false, "neighbor has no back-neighbor."); + return false; + } + if( &(*(n->neighbor(mirror_idx))) != this ) + { + if( verbose ) CGAL_warning_msg(false, "neighbor does not point back to correct full cell."); + return false; + } + } + } + return true; + } + +private: + // access to data members: + Full_cell_handle_array & neighbors() {return combinatorics_.neighbors_; } + const Full_cell_handle_array & neighbors() const {return combinatorics_.neighbors_; } + Vertex_handle_array & vertices() {return combinatorics_.vertices_; } + const Vertex_handle_array & vertices() const {return combinatorics_.vertices_; } + + // DATA MEMBERS + Combinatorics combinatorics_; + mutable TDS_data tds_data_; +}; + +// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS: + +template < typename TDS, typename SSP > +std::ostream & +operator<<(std::ostream & O, const Triangulation_ds_full_cell &) /* Concept */ +{ + /*if( is_ascii(O) ) + { + // os << '\n'; + } + else {}*/ + return O; +} + +template < typename TDS, typename SSP > +std::istream & +operator>>(std::istream & I, Triangulation_ds_full_cell &) /* Concept */ +{ + /*if( is_ascii(I) ) + {} + else {}*/ + return I; +} + +// Special case: specialization when template parameter is void. + +// we must declare it for each possible full_cell storage policy because : +// (GCC error:) default template arguments may not be used in partial specializations +template< typename StoragePolicy > +class Triangulation_ds_full_cell +{ +public: + typedef internal::Triangulation::Dummy_TDS TDS; + typedef TDS Triangulation_data_structure; + typedef TDS::Vertex_handle Vertex_handle; + typedef TDS::Vertex_const_handle Vertex_const_handle; + typedef TDS::Full_cell_handle Full_cell_handle; + typedef TDS::Full_cell_const_handle Full_cell_const_handle; + typedef TDS::Vertex_handle_const_iterator Vertex_handle_const_iterator; + typedef TDS::Full_cell_data TDS_data; + template + struct Rebind_TDS + { + typedef Triangulation_ds_full_cell Other; + }; + Vertex_handle_const_iterator vertices_begin(); + Vertex_handle_const_iterator vertices_end(); +}; + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_DS_FULL_CELL_H diff --git a/include/gudhi_patches/CGAL/Triangulation_ds_vertex.h b/include/gudhi_patches/CGAL/Triangulation_ds_vertex.h new file mode 100644 index 00000000..381b97e1 --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_ds_vertex.h @@ -0,0 +1,154 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_DS_VERTEX_H +#define CGAL_TRIANGULATION_DS_VERTEX_H + +#include +#include + +namespace CGAL { + +/* The template parameter TDS must be a model of the concept + * 'TriangulationDataStructure' that stores vertices of type + * 'Triangulation_ds_vertex' + */ +template< class TDS = void > +class Triangulation_ds_vertex +{ + typedef Triangulation_ds_vertex Self; + +public: + typedef TDS Triangulation_data_structure; + typedef typename TDS::Full_cell_handle Full_cell_handle; /* Concept */ + + template + struct Rebind_TDS /* Concept */ + { + typedef Triangulation_ds_vertex Other; + }; + +protected: // DATA MEMBERS + Full_cell_handle full_cell_; // A handle to an incident full_cell + +public: + // Constructs a vertex with incident full_cell 's' + Triangulation_ds_vertex(Full_cell_handle s) : full_cell_(s) /* Concept */ + { + CGAL_assertion( Full_cell_handle() != s ); + } + // Constructs a vertex with no incident full_cell + Triangulation_ds_vertex() : full_cell_() {} /* Concept */ + + ~Triangulation_ds_vertex() {} + + /// Set 's' as an incident full_cell + void set_full_cell(Full_cell_handle s) /* Concept */ + { + full_cell_ = s; + } + + /// Returns a full_cell incident to the vertex + Full_cell_handle full_cell() const /* Concept */ + { + return full_cell_; + } + + bool is_valid(bool verbose = false, int /* level */ = 0) const /* Concept */ + { + if( Full_cell_handle() == full_cell() ) + { + if( verbose ) + CGAL_warning_msg(false, "vertex has no incident full cell."); + return false; + } + bool found(false); + // These two typename below are OK because TDS fullfils the + // TriangulationDataStructure concept. + typename TDS::Full_cell::Vertex_handle_iterator vit(full_cell()->vertices_begin()); + typedef typename TDS::Vertex_handle Vertex_handle; + while( vit != full_cell()->vertices_end() ) + { + if( Vertex_handle() == *vit ) + break; // The full cell has no more vertices + if( this == &(**vit) ) + { + found = true; + break; + } + ++vit; + } + if( ! found ) + { + if( verbose ) + CGAL_warning_msg(false, "vertex's adjacent full cell does not contain that vertex."); + return false; + } + return true; + } + +public: // FOR MEMORY MANAGEMENT + + void* for_compact_container() const { return full_cell_.for_compact_container(); } + void* & for_compact_container() { return full_cell_.for_compact_container(); } + +}; // end of Triangulation_ds_vertex + +// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS: + +template < class TDS > +std::istream & +operator>>(std::istream & is, Triangulation_ds_vertex &) /* Concept */ +{ + /*if( is_ascii(is) ) + {} + else {}*/ + return is; +} + +template< class TDS > +std::ostream & +operator<<(std::ostream & os, const Triangulation_ds_vertex &) /* Concept */ +{ + /*if( is_ascii(os) ) + { + os << '\n'; + } + else {}*/ + return os; +} + +// Special case: specialization when template parameter is void. + +template<> +class Triangulation_ds_vertex +{ +public: + typedef internal::Triangulation::Dummy_TDS Triangulation_data_structure; + typedef Triangulation_data_structure::Full_cell_handle Full_cell_handle; /* Concept */ + template + struct Rebind_TDS /* Concept */ + { + typedef Triangulation_ds_vertex Other; + }; +}; + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_DS_VERTEX_H diff --git a/include/gudhi_patches/CGAL/Triangulation_face.h b/include/gudhi_patches/CGAL/Triangulation_face.h new file mode 100644 index 00000000..bc9c1781 --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_face.h @@ -0,0 +1,111 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_FACE_H +#define CGAL_TRIANGULATION_FACE_H + +#include +#include + +namespace CGAL { + +template< typename TDS > +class Triangulation_face +{ + typedef typename internal::Dimen_plus_one::type Dimen_plus; +public: + typedef TDS Triangulation_data_structure; + typedef typename TDS::Full_cell_handle Full_cell_handle; /* Concept */ + typedef typename TDS::Vertex_handle Vertex_handle; /* Concept */ + typedef internal::S_or_D_array Indices; + +protected: + Full_cell_handle full_cell_; + Indices indices_; + +public: + explicit Triangulation_face(Full_cell_handle s) /* Concept */ + : full_cell_(s), indices_(s->maximal_dimension()+2) + { + CGAL_assertion( Full_cell_handle() != s ); + clear(); + } + + explicit Triangulation_face(const int maximal_dim) /* Concept */ + : full_cell_(), indices_(maximal_dim+2) + { + clear(); + } + + Triangulation_face(const Triangulation_face & f) /* Concept */ + : full_cell_(f.full_cell_), indices_(f.indices_) + {} + + int face_dimension() const /* Concept */ + { + int i(0); + while( -1 != indices_[i] ) ++i; + return (i-1); + } + + Full_cell_handle full_cell() const /* Concept */ + { + return full_cell_; + } + + int index(const int i) const /* Concept */ + { + CGAL_precondition( (0 <= i) && (i <= face_dimension()) ); + return indices_[i]; + } + + Vertex_handle vertex(const int i) const /* Concept */ + { + int j = index(i); + if( j == -1 ) + return Vertex_handle(); + return full_cell()->vertex(j); + } + +// - - - - - - - - - - - - - - - - - - UPDATE FUNCTIONS + + void clear() /* Concept */ + { + const std::size_t d = indices_.size(); + for(std::size_t i = 0; i < d; ++i ) + indices_[i] = -1; + } + + void set_full_cell(Full_cell_handle s) /* Concept */ + { + CGAL_precondition( Full_cell_handle() != s ); + full_cell_ = s; + } + + void set_index(const int i, const int idx) /* Concept */ + { + CGAL_precondition( (0 <= i) && ((size_t)i+1 < indices_.size()) ); + CGAL_precondition( (0 <= idx) && ((size_t)idx < indices_.size()) ); + indices_[i] = idx; + } +}; + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_FACE_H diff --git a/include/gudhi_patches/CGAL/Triangulation_full_cell.h b/include/gudhi_patches/CGAL/Triangulation_full_cell.h new file mode 100644 index 00000000..a0c5246f --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_full_cell.h @@ -0,0 +1,148 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_SIMPLEX_H +#define CGAL_TRIANGULATION_SIMPLEX_H + +#include +#include +#include +#include + +namespace CGAL { + +struct No_full_cell_data {}; + +template< class TriangulationTraits, typename Data_ = No_full_cell_data, class TDSFullCell = Default > +class Triangulation_full_cell : public Default::Get >::type +{ + // The default type for TDSFullCell is Triangulation_ds_full_cell<> : + typedef typename Default::Get >::type + Base; + typedef Triangulation_full_cell Self; +public: + typedef Data_ Data; + typedef typename Base::Vertex_handle Vertex_handle; + typedef typename Base::Vertex_const_handle Vertex_const_handle; + typedef typename Base::Vertex_handle_const_iterator Vertex_handle_const_iterator; + typedef typename Base::Full_cell_const_handle Full_cell_const_handle; + typedef typename TriangulationTraits::Point_d Point; + typedef typename TriangulationTraits::Point_d Point_d; + +private: // DATA MEMBERS + Data data_; + +public: + + using Base::vertices_begin; + using Base::vertices_end; + + template< class TDS2 > + struct Rebind_TDS + { + typedef typename Base::template Rebind_TDS::Other TDSFullCell2; + typedef Triangulation_full_cell Other; + }; + + Triangulation_full_cell(const int d) + : Base(d), data_() {} + + Triangulation_full_cell(const Self & s) + : Base(s), data_(s.data_) {} + + const Data & data() const + { + return data_; + } + + Data & data() + { + return data_; + } + + struct Point_from_vertex_handle + { + typedef Vertex_handle argument_type; + typedef Point result_type; + result_type & operator()(argument_type & x) const + { + return x->point(); + } + const result_type & operator()(const argument_type & x) const + { + return x->point(); + } + }; + +protected: + + typedef CGAL::Iterator_project< + Vertex_handle_const_iterator, + internal::Triangulation::Point_from_vertex_handle + > Point_const_iterator; + + Point_const_iterator points_begin() const + { return Point_const_iterator(Base::vertices_begin()); } + Point_const_iterator points_end() const + { return Point_const_iterator(Base::vertices_end()); } +}; + +// FUNCTIONS THAT ARE NOT MEMBER FUNCTIONS: + +inline +std::istream & +operator>>(std::istream & is, No_full_cell_data &) +{ + return is; +} + +inline +std::ostream & +operator<<(std::ostream & os, const No_full_cell_data &) +{ + return os; +} + +template < typename TDS, typename Data, typename SSP > +std::ostream & +operator<<(std::ostream & O, const Triangulation_full_cell & s) +{ + /*if( is_ascii(O) ) + { + // os << '\n'; + } + else {}*/ + O << s.data(); + return O; +} + +template < typename TDS, typename Data, typename SSP > +std::istream & +operator>>(std::istream & I, Triangulation_full_cell & s) +{ + /*if( is_ascii(I) ) + {} + else {}*/ + I >> s.data(); + return I; +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_SIMPLEX_H diff --git a/include/gudhi_patches/CGAL/Triangulation_vertex.h b/include/gudhi_patches/CGAL/Triangulation_vertex.h new file mode 100644 index 00000000..f364717f --- /dev/null +++ b/include/gudhi_patches/CGAL/Triangulation_vertex.h @@ -0,0 +1,128 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_TRIANGULATION_VERTEX_H +#define CGAL_TRIANGULATION_VERTEX_H + +#include +#include + +namespace CGAL { + +struct No_vertex_data {}; + +template< class TriangulationTraits, typename Data_ = No_vertex_data, class TDSVertex = Default > +class Triangulation_vertex : public Default::Get >::type +{ + // The default type for TDSVertex is Triangulation_ds_vertex<> : + typedef typename Default::Get >::type + Base; + typedef Triangulation_vertex Self; +public: + typedef Data_ Data; + typedef typename TriangulationTraits::Point_d Point; + typedef typename TriangulationTraits::Point_d Point_d; + typedef typename Base::Full_cell_handle Full_cell_handle; + + template + struct Rebind_TDS + { + typedef typename Base::template Rebind_TDS::Other TDSVertex2; + typedef Triangulation_vertex Other; + }; + +private: // DATA MEMBERS + Point point_; + Data data_; + +public: + template< typename T > + Triangulation_vertex(Full_cell_handle s, const Point & p, const T & t) + : Base(s), point_(p), data_(t) {} + Triangulation_vertex(Full_cell_handle s, const Point & p) + : Base(s), point_(p), data_() {} + template< typename T > + Triangulation_vertex(const Point & p, const T & t) + : Base(), point_(p), data_(t) {} + Triangulation_vertex(const Point & p) + : Base(), point_(p), data_() {} + Triangulation_vertex() : Base(), point_(), data_() {} + + ~Triangulation_vertex() {} + + /// Set the position in space of the vertex to 'p' + void set_point(const Point & p) + { + point_ = p; + } + + /// Returns the position in space of the vertex + const Point & point() const + { + return point_; + } + + const Data & data() const + { + return data_; + } + + Data & data() + { + return data_; + } + +}; // end of Triangulation_vertex + +// NON CLASS-MEMBER FUNCTIONS + +inline +std::istream & +operator>>(std::istream & is, No_vertex_data &) +{ + return is; +} + +inline +std::ostream & +operator<<(std::ostream & os, const No_vertex_data &) +{ + return os; +} + +template < class A, typename Data, class B > +std::istream & +operator>>(std::istream & is, Triangulation_vertex & v) +{ + is >> v.point(); + return (is >> v.data()); +} + +template< class A, typename Data, class B > +std::ostream & +operator<<(std::ostream & os, const Triangulation_vertex & v) +{ + os << v.point(); + os << v.data(); + return os; +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_VERTEX_H diff --git a/include/gudhi_patches/CGAL/argument_swaps.h b/include/gudhi_patches/CGAL/argument_swaps.h new file mode 100644 index 00000000..aa16f29b --- /dev/null +++ b/include/gudhi_patches/CGAL/argument_swaps.h @@ -0,0 +1,88 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_ARGUMENT_SWAPS_H +#define CGAL_ARGUMENT_SWAPS_H + +#include +#include + +#ifndef CGAL_CXX11 +#include +#include +#endif + +namespace CGAL { + +#ifdef CGAL_CXX11 + +namespace internal { + +template struct Apply_to_last_then_rest_; + +template +struct Apply_to_last_then_rest_ { + typedef typename Apply_to_last_then_rest_::result_type result_type; + inline result_type operator()(F&&f,T&&t,U&&...u)const{ + return Apply_to_last_then_rest_()( + std::forward(f), + std::forward(u)..., + std::forward(t)); + } +}; + +template +struct Apply_to_last_then_rest_<0,F,T,U...> { + typedef decltype(std::declval()(std::declval(), std::declval()...)) result_type; + inline result_type operator()(F&&f,T&&t,U&&...u)const{ + return std::forward(f)(std::forward(t), std::forward(u)...); + } +}; + +} // namespace internal + + +struct Apply_to_last_then_rest { + template inline + typename internal::Apply_to_last_then_rest_::result_type + operator()(F&&f,T&&t,U&&...u)const{ + return internal::Apply_to_last_then_rest_()( + std::forward(f), + std::forward(t), + std::forward(u)...); + } +}; + +#else // CGAL_CXX11 + +struct Apply_to_last_then_rest { +#define CGAL_CODE(Z,N,_) template \ + typename boost::result_of::type \ + operator()(F const&f, BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t), T const&t) const { \ + return f(t,BOOST_PP_ENUM_PARAMS(N,t)); \ + } + BOOST_PP_REPEAT_FROM_TO(1,11,CGAL_CODE,_) +#undef CGAL_CODE +}; + +#endif // CGAL_CXX11 + +} // namespace CGAL + +#endif // CGAL_ARGUMENT_SWAPS_H diff --git a/include/gudhi_patches/CGAL/determinant_of_vectors.h b/include/gudhi_patches/CGAL/determinant_of_vectors.h new file mode 100644 index 00000000..e1bad64e --- /dev/null +++ b/include/gudhi_patches/CGAL/determinant_of_vectors.h @@ -0,0 +1,117 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_DETVEC_H +#define CGAL_DETVEC_H +#include +#include + +namespace CGAL { + // TODO: determine whether it is better to pass them by lines or columns. + + template inline + NT determinant_of_vectors(Vector const&a, Vector const&b){ + return determinant(a[0],a[1],b[0],b[1]); + } + template inline + typename Sgn::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b){ + return sign_of_determinant(a[0],a[1],b[0],b[1]); + } + + template + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c){ + return determinant(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2]); + } + template + typename Sgn::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c){ + return sign_of_determinant(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2]); + } + + template + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return determinant( + a[0],a[1],a[2],a[3], + b[0],b[1],b[2],b[3], + c[0],c[1],c[2],c[3], + d[0],d[1],d[2],d[3]); + } + template + typename Sgn::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return sign_of_determinant( + a[0],a[1],a[2],a[3], + b[0],b[1],b[2],b[3], + c[0],c[1],c[2],c[3], + d[0],d[1],d[2],d[3]); + } + + template + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return determinant( + a[0],a[1],a[2],a[3],a[4], + b[0],b[1],b[2],b[3],b[4], + c[0],c[1],c[2],c[3],c[4], + d[0],d[1],d[2],d[3],d[4], + e[0],e[1],e[2],e[3],e[4]); + } + template + typename Sgn::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return sign_of_determinant( + a[0],a[1],a[2],a[3],a[4], + b[0],b[1],b[2],b[3],b[4], + c[0],c[1],c[2],c[3],c[4], + d[0],d[1],d[2],d[3],d[4], + e[0],e[1],e[2],e[3],e[4]); + } + + template + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return determinant( + a[0],a[1],a[2],a[3],a[4],a[5], + b[0],b[1],b[2],b[3],b[4],b[5], + c[0],c[1],c[2],c[3],c[4],c[5], + d[0],d[1],d[2],d[3],d[4],d[5], + e[0],e[1],e[2],e[3],e[4],e[5], + f[0],f[1],f[2],f[3],f[4],f[5]); + } + template + typename Sgn::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return sign_of_determinant( + a[0],a[1],a[2],a[3],a[4],a[5], + b[0],b[1],b[2],b[3],b[4],b[5], + c[0],c[1],c[2],c[3],c[4],c[5], + d[0],d[1],d[2],d[3],d[4],d[5], + e[0],e[1],e[2],e[3],e[4],e[5], + f[0],f[1],f[2],f[3],f[4],f[5]); + } + +} +#endif diff --git a/include/gudhi_patches/CGAL/internal/Combination_enumerator.h b/include/gudhi_patches/CGAL/internal/Combination_enumerator.h new file mode 100644 index 00000000..f411e827 --- /dev/null +++ b/include/gudhi_patches/CGAL/internal/Combination_enumerator.h @@ -0,0 +1,148 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_INTERNAL_COMBINATION_ENUMERATOR_H +#define CGAL_INTERNAL_COMBINATION_ENUMERATOR_H + +#include +#include + +namespace CGAL { + +namespace internal { + +class Combination_enumerator +{ + // types and member data + typedef std::vector Combination; + Combination combi_; + const int k_; + const int min_; + const int max_; + const int max_at_pos_0_; + +public: + + // For generating all the combinations of |k| distinct elements in the + // interval [min, max] (both included) + Combination_enumerator(const int k, const int min, const int max) + : combi_(k), k_(k), min_(min), max_(max), max_at_pos_0_(max + 1 - k) + { + CGAL_assertion_msg( min <= max, "min is larger than max"); + CGAL_assertion_msg( 1 <= k && k <= ( max - min + 1 ), "wrong value of k"); + init(); + } + + Combination_enumerator(const Combination_enumerator & c) + : combi_(c.combi_), k_(c.k_), min_(c.min_), max_(c.max_), max_at_pos_0_(c.max_at_pos_0_) + {} + + int number_of_elements() + { + return k_; + } + + void init() + { + combi_.resize(k_); + for( int i = 0; i < k_; ++i ) + element(i) = min_ + i; + } + + bool end() const + { + return ( element(0) > max_at_pos_0_ ); + } + + int element(const int i) const + { + CGAL_assertion( 0 <= i && i < k_ ); + return combi_[i]; + } + + int & element(const int i) + { + CGAL_assertion( 0 <= i && i < k_ ); + return combi_[i]; + } + + int operator[](const int i) const + { + return element(i); + } + + int & operator[](const int i) + { + return element(i); + } + + void operator++() + { + int i = k_ - 1; + int max_at_pos_i(max_); + while( ( i >= 0 ) && ( element(i) >= max_at_pos_i ) ) + { + --i; + --max_at_pos_i; + } + if( -1 == i ) + { + if( element(0) == max_at_pos_0_ ) + ++element(0); // mark then end of the enumeration with an impossible value + // Note than when we have arrived at the end of the enumeration, applying + // operator++() again does not change anything, so it is safe to + // apply it too many times. + } + else + { + ++element(i); + for( int j = i + 1; j < k_; ++j ) + element(j) = element(i) + j - i; + } + } + + Combination_enumerator operator++(int) + { + Combination_enumerator tmp(*this); + ++(*this); + return tmp; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - TESTING +#if 0 + void test() + { + std::cerr << '\n'; + while( ! end() ) + { + std::cerr << '\n'; + for( int i = 0; i < k_; ++i ) + std::cerr << element(i) << ' '; + ++(*this); + } + init(); + } +#endif +}; + +} // end of namespace internal + +} // end of namespace CGAL + +#endif // CGAL_INTERNAL_COMBINATION_ENUMERATOR_H diff --git a/include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h b/include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h new file mode 100644 index 00000000..ee6195d9 --- /dev/null +++ b/include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h @@ -0,0 +1,116 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_INTERNAL_STATIC_OR_DYNAMIC_ARRAY_H +#define CGAL_INTERNAL_STATIC_OR_DYNAMIC_ARRAY_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + +// Utility for adding one to an Dimension_tag: + +template +struct Dimen_plus_one; + +template<> +struct Dimen_plus_one +{ + typedef Dynamic_dimension_tag type; +}; + +template +struct Dimen_plus_one > +{ + typedef Dimension_tag type; +}; + +// A SMALL CONTAINER UTILITY FOR DYNAMIC/STATIC MEMORY MANAGEMENT + +// stores an array of static or dynamic size, depending on template parameter . + +template< typename Containee, typename D, bool WithCompactContainerHelper = false> + struct S_or_D_array; // S = static, D = dynamic + +// The case of static size: +template< typename Containee, int D, bool WithCompactContainerHelper > +struct S_or_D_array< Containee, Dimension_tag< D >, WithCompactContainerHelper > +: public array +{ + typedef array Base; + S_or_D_array(const int) + : Base() + {} + S_or_D_array(const int, const Containee & c) + : Base() + { + assign(c); + } + void* for_compact_container() const + { + return (*this)[0].for_compact_container(); + } + void* & for_compact_container() + { + return (*this)[0].for_compact_container(); + } +}; + +// The case of dynamic size +template< typename Containee > +struct S_or_D_array< Containee, Dynamic_dimension_tag, false > +: public std::vector +{ + typedef std::vector Base; + // TODO: maybe we should use some "small-vector-optimized" class. + S_or_D_array(const int d) + : Base(d) + {} + S_or_D_array(const int d, const Containee & c) + : Base(d, c) + {} +}; + +// The case of dynamic size with for_compact_container +template< typename Containee > +struct S_or_D_array< Containee, Dynamic_dimension_tag, true > +: public std::vector +{ + typedef std::vector Base; + S_or_D_array(const int d) + : Base(d), fcc_(NULL) + {} + S_or_D_array(const int d, const Containee & c) + : Base(d, c), fcc_(NULL) + {} + void* fcc_; + void* for_compact_container() const { return fcc_; } + void* & for_compact_container() { return fcc_; } +}; + +} // end of namespace internal + +} // end of namespace CGAL + +#endif // CGAL_INTERNAL_STATIC_OR_DYNAMIC_ARRAY_H diff --git a/include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h b/include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h new file mode 100644 index 00000000..b3a0ec98 --- /dev/null +++ b/include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h @@ -0,0 +1,49 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_INTERNAL_TRIANGULATION_DUMMY_TDS_H +#define CGAL_INTERNAL_TRIANGULATION_DUMMY_TDS_H + +namespace CGAL { + +namespace internal { +namespace Triangulation { + +struct Dummy_TDS +{ + struct Vertex {}; + struct Vertex_handle {}; + struct Vertex_iterator {}; + struct Vertex_const_handle {}; + struct Vertex_const_iterator {}; + struct Full_cell {}; + struct Full_cell_handle {}; + struct Full_cell_iterator {}; + struct Full_cell_const_handle {}; + struct Full_cell_const_iterator {}; + struct Vertex_handle_const_iterator {}; + struct Full_cell_data {}; +}; + +} // namespace Triangulation +} // namespace internal + +} //namespace CGAL + +#endif // CGAL_INTERNAL_TRIANGULATION_DUMMY_TDS_H diff --git a/include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h b/include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h new file mode 100644 index 00000000..7e360026 --- /dev/null +++ b/include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h @@ -0,0 +1,154 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus (Well... `copy, paste and hack' of Monique Teillaud's work) + +#ifndef CGAL_INTERNAL_TRIANGULATION_TRIANGULATION_DS_ITERATORS_H +#define CGAL_INTERNAL_TRIANGULATION_TRIANGULATION_DS_ITERATORS_H + +namespace CGAL { + +namespace internal { +namespace Triangulation { + +template< typename TDS > +class Triangulation_ds_facet_iterator +{ + typedef typename TDS::Full_cell_handle Full_cell_handle; + typedef typename TDS::Facet Facet; + + typedef Facet value_type; + typedef const Facet * pointer; + typedef const Facet & reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef Triangulation_ds_facet_iterator Facet_iterator; + + TDS & tds_; + Facet ft_; + const int cur_dim_; + +public: + Triangulation_ds_facet_iterator(TDS & tds) + : tds_(tds), ft_(tds.full_cells_begin(), 0), cur_dim_(tds.current_dimension()) + { + CGAL_assertion( cur_dim_ > 0 ); + while( ! canonical() ) + raw_increment(); + } + + Triangulation_ds_facet_iterator(TDS & tds, int) + : tds_(tds), ft_(tds.full_cells_end(), 0), cur_dim_(tds.current_dimension()) + { + CGAL_assertion( cur_dim_ > 0 ); + CGAL_assertion( canonical() ); + } + + Facet_iterator & operator++() + { + increment(); + return (*this); + } + + Facet_iterator operator++(int) + { + Facet_iterator tmp(*this); + increment(); + return tmp; + } + + Facet_iterator & operator--() + { + decrement(); + return (*this); + } + + Facet_iterator operator--(int) + { + Facet_iterator tmp(*this); + decrement(); + return tmp; + } + + bool operator==(const Facet_iterator & fi) const + { + return (&tds_ == &fi.tds_) && + (tds_.index_of_covertex(ft_) == fi.tds_.index_of_covertex(fi.ft_)) && + (tds_.full_cell(ft_) == fi.tds_.full_cell(fi.ft_)); + } + + bool operator!=(const Facet_iterator & fi) const + { + return !(*this == fi); + } + + reference operator*() const + { + return ft_; + } + + pointer operator->() const + { + return &ft_; + } + +private: + bool canonical() + { + if( tds_.full_cells_end() == tds_.full_cell(ft_) ) + return ( 0 == tds_.index_of_covertex(ft_) ); + return ( tds_.full_cell(ft_) < + tds_.full_cell(ft_)->neighbor(tds_.index_of_covertex(ft_)) ); + } + + void raw_decrement() + { + int i = tds_.index_of_covertex(ft_); + if( i == 0 ) + ft_ = Facet(--tds_.full_cell(ft_), cur_dim_); + else + ft_ = Facet(tds_.full_cell(ft_), i - 1); + } + + void raw_increment() + { + int i = tds_.index_of_covertex(ft_); + if( i == cur_dim_ ) + ft_ = Facet(++tds_.full_cell(ft_), 0); + else + ft_ = Facet(tds_.full_cell(ft_), i + 1); + } + + void decrement() + { + do { raw_decrement(); } while( ! canonical() ); + } + + void increment() + { + do { raw_increment(); } while( ! canonical() ); + } +}; + +} // namespace Triangulation +} // namespace internal + +} //namespace CGAL + +#endif // CGAL_INTERNAL_TRIANGULATION_TRIANGULATION_DS_ITERATORS_H diff --git a/include/gudhi_patches/CGAL/internal/Triangulation/utilities.h b/include/gudhi_patches/CGAL/internal/Triangulation/utilities.h new file mode 100644 index 00000000..a1ffc775 --- /dev/null +++ b/include/gudhi_patches/CGAL/internal/Triangulation/utilities.h @@ -0,0 +1,154 @@ +// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Samuel Hornus + +#ifndef CGAL_INTERNAL_TRIANGULATION_UTILITIES_H +#define CGAL_INTERNAL_TRIANGULATION_UTILITIES_H + +#include + +namespace CGAL { + +namespace internal { +namespace Triangulation { + +template< class TDS > +struct Dark_full_cell_data +{ + typedef typename TDS::Full_cell_handle Full_cell_handle; + Full_cell_handle light_copy_; + int count_; + Dark_full_cell_data() : light_copy_(), count_(0) {} +}; + +template< class TDS > +struct Compare_faces_with_common_first_vertex +{ + typedef typename TDS::Face Face; + + const int d_; + +public: + + Compare_faces_with_common_first_vertex(const int d) + : d_(d) + { + CGAL_assertion( 0 < d ); + } + + explicit Compare_faces_with_common_first_vertex(); + + bool operator()(const Face & left, const Face & right) const + { + CGAL_assertion( d_ == left.face_dimension() ); + CGAL_assertion( d_ == right.face_dimension() ); + for( int i = 1; i <= d_; ++i ) + { + if( left.vertex(i) < right.vertex(i) ) + return true; + if( right.vertex(i) < left.vertex(i) ) + return false; + } + return false; + } +}; + +template< class T > +struct Compare_vertices_for_upper_face +{ + typedef typename T::Vertex_const_handle VCH; + + const T & t_; + +public: + + Compare_vertices_for_upper_face(const T & t) + : t_(t) + {} + + explicit Compare_vertices_for_upper_face(); + + bool operator()(const VCH & left, const VCH & right) const + { + if( left == right ) + return false; + if( t_.is_infinite(left) ) + return true; + if( t_.is_infinite(right) ) + return false; + return left < right; + } +}; + +template< class T > +struct Compare_points_for_perturbation +{ + typedef typename T::Geom_traits::Point_d Point; + + const T & t_; + +public: + + Compare_points_for_perturbation(const T & t) + : t_(t) + {} + + explicit Compare_points_for_perturbation(); + + bool operator()(const Point * left, const Point * right) const + { + return (SMALLER == t_.geom_traits().compare_lexicographically_d_object()(*left, *right)); + } +}; + +template< class T > +struct Point_from_pointer +{ + typedef const typename T::Geom_traits::Point_d * argument_type; + typedef const typename T::Geom_traits::Point_d result_type; + result_type & operator()(argument_type & x) const + { + return (*x); + } + const result_type & operator()(const argument_type & x) const + { + return (*x); + } +}; + +template< typename Vertex_handle, typename Point > +struct Point_from_vertex_handle +{ + typedef Vertex_handle argument_type; + typedef Point result_type; + result_type & operator()(argument_type & x) const + { + return x->point(); + } + const result_type & operator()(const argument_type & x) const + { + return x->point(); + } +}; + +} // namespace Triangulation +} // namespace internal + +} //namespace CGAL + +#endif // CGAL_INTERNAL_TRIANGULATION_UTILITIES_H diff --git a/include/gudhi_patches/CGAL/iterator_from_indices.h b/include/gudhi_patches/CGAL/iterator_from_indices.h new file mode 100644 index 00000000..110bb4be --- /dev/null +++ b/include/gudhi_patches/CGAL/iterator_from_indices.h @@ -0,0 +1,75 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_ITERATOR_FROM_INDICES_H +#define CGAL_ITERATOR_FROM_INDICES_H +#include +#include +namespace CGAL { +template +struct Default_coordinate_access { + typedef Ref_ result_type; + template Ref_ operator()(T const& t, std::ptrdiff_t i)const{ + return t[i]; + } +}; + +//TODO: default type for Value_: typename same_cv::type::value_type>::type +template ()[0]) +#else + Value_& +#endif + , class Coord_access = Default_coordinate_access + > +class Iterator_from_indices +: public boost::iterator_facade, + Value_, std::bidirectional_iterator_tag, Ref_> +{ + friend class boost::iterator_core_access; + //FIXME: use int to save space + //TODO: use a tuple to save space when Coord_access is empty + typedef std::ptrdiff_t index_t; + Container_* cont; + index_t index; + Coord_access ca; + void increment(){ ++index; } + void decrement(){ --index; } + void advance(std::ptrdiff_t n){ index+=n; } + ptrdiff_t distance_to(Iterator_from_indices const& other)const{ + return other.index-index; + } + bool equal(Iterator_from_indices const& other)const{ + return index==other.index; + } + Ref_ dereference()const{ + //FIXME: use the functor properly + //Uh, and what did I mean by that? + return ca(*cont,index); + } + public: + Iterator_from_indices(Container_& cont_,std::size_t n) + : cont(&cont_), index(n) {} + template + Iterator_from_indices(Container_& cont_,std::size_t n,T const&t) + : cont(&cont_), index(n), ca(t) {} +}; +} +#endif // CGAL_ITERATOR_FROM_INDICES_H diff --git a/include/gudhi_patches/CGAL/transforming_iterator.h b/include/gudhi_patches/CGAL/transforming_iterator.h new file mode 100644 index 00000000..15ea19a5 --- /dev/null +++ b/include/gudhi_patches/CGAL/transforming_iterator.h @@ -0,0 +1,123 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_TRANSFORMING_ITERATOR_H +#define CGAL_TRANSFORMING_ITERATOR_H +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Inspired by the boost version, but more compact and +// without any iterator_category games. + +namespace CGAL { +namespace internal { + +// non-empty case +template::value> struct Functor_as_base { + Functor_as_base(){} + Functor_as_base(T const& t):f(t){} + //template Functor_as_base(Functor_as_base const&g):f(g.functor()){} + T const& functor()const{return f;} + T & functor() {return f;} + private: + T f; +}; + +// empty case +template struct Functor_as_base : public T { + Functor_as_base(){} + Functor_as_base(T const& t):T(t){} + //template Functor_as_base(Functor_as_base const&g):T(g.functor()){} + T const& functor()const{return *this;} + T & functor() {return *this;} +}; + +template +class transforming_iterator_helper +{ + typedef std::iterator_traits Iter_traits; + typedef typename Iter_traits::reference Iter_ref; + typedef typename Default::Get()(std::declval())) +#else + typename boost::result_of::type + // should be reference instead of value_type +#endif + >::type reference_; + + typedef typename Default::Get::type>::type>::type value_type; + + // Crappy heuristic. If we have *it that returns a Weighted_point and F that returns a reference to the Point contained in the Weighted_point it takes as argument, we do NOT want the transformed iterator to return a reference to the temporary *it. On the other hand, if *it returns an int n, and F returns a reference to array[n] it is not so good to lose the reference. This probably should be done elsewhere and should at least be made optional... + typedef typename boost::mpl::if_< + boost::mpl::or_, + boost::is_integral >, + reference_, value_type>::type reference; + + public: + typedef boost::iterator_adaptor< + Derived, + Iter, + value_type, + typename Iter_traits::iterator_category, + reference + > type; +}; +} + +template +class transforming_iterator +: public internal::transforming_iterator_helper,F,Iter,Ref,Val>::type, +private internal::Functor_as_base +{ + friend class boost::iterator_core_access; + typedef typename internal::transforming_iterator_helper::type Base; + typedef internal::Functor_as_base Functor_base; + typename Base::reference dereference()const{ + return functor()(*this->base_reference()); + } + public: + using Functor_base::functor; + transforming_iterator(){} + explicit transforming_iterator(Iter i,F const& f=F()) + :Base(i),Functor_base(f){} + template + transforming_iterator( + transforming_iterator const&i, + typename boost::enable_if_convertible::type* = 0, + typename boost::enable_if_convertible::type* = 0) + : Base(i.base()),Functor_base(i.functor()) {} + +}; + +template inline +transforming_iterator make_transforming_iterator(Iter i, F const&f=F()) { + return transforming_iterator(i,f); +} + +} + +#endif // CGAL_TRANSFORMING_ITERATOR_H diff --git a/include/gudhi_patches/CGAL/transforming_pair_iterator.h b/include/gudhi_patches/CGAL/transforming_pair_iterator.h new file mode 100644 index 00000000..48dac132 --- /dev/null +++ b/include/gudhi_patches/CGAL/transforming_pair_iterator.h @@ -0,0 +1,127 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_TRANSFORMING_PAIR_ITERATOR_H +#define CGAL_TRANSFORMING_PAIR_ITERATOR_H +// Should be a combination of transform_iterator and zip_iterator, +// but boost's iterator_category games are a pain. + +#include +#include +#include + + + + +namespace CGAL { +namespace internal { +template ::value> +struct Min_category { + CGAL_static_assertion((boost::is_convertible::value)); + typedef Cat1 type; +}; + +template +struct Min_category { + typedef Cat2 type; +}; + + +template +class transforming_pair_iterator_helper +{ + typedef typename Min_category< + typename std::iterator_traits::iterator_category, + typename std::iterator_traits::iterator_category> + ::type iterator_category; + + typedef typename Default::Get()(std::declval::reference>(),std::declval::reference>())) +#else + typename boost::result_of::value_type,typename std::iterator_traits::value_type)>::type + // should be reference instead of value_type +#endif + >::type reference; + + typedef typename Default::Get::type>::type>::type value_type; + + public: + typedef boost::iterator_facade< + Derived, + value_type, + iterator_category, + reference + // expect ptrdiff_t is good enough for difference + > type; +}; +} + +template +class transforming_pair_iterator +: public internal::transforming_pair_iterator_helper,F,It1,It2,Ref,Val>::type, +private internal::Functor_as_base +{ + It1 iter1; It2 iter2; + friend class boost::iterator_core_access; + typedef typename internal::transforming_pair_iterator_helper::type Base; + typedef internal::Functor_as_base Functor_base; + typename Base::reference dereference()const{ + return functor()(*iter1,*iter2); + } + bool equal(transforming_pair_iterator const&i)const{ + bool b=(iter1==i.iter1); + CGAL_assertion(b==(iter2==i.iter2)); + //FIXME: or do we want only one driving iterator + return b; + } + void increment(){ ++iter1; ++iter2; } + void decrement(){ --iter1; --iter2; } + void advance(std::ptrdiff_t n){ + std::advance(iter1,n); + std::advance(iter2,n); + } + std::ptrdiff_t distance_to(transforming_pair_iterator const&i)const{ + std::ptrdiff_t dist=std::distance(iter1,i.iter1); + CGAL_assertion(dist==std::distance(iter2,i.iter2)); + return dist; + } + public: + using Functor_base::functor; + transforming_pair_iterator(){} + explicit transforming_pair_iterator(It1 i1,It2 i2,F const& f=F()) + :Functor_base(f),iter1(i1),iter2(i2){} + template + transforming_pair_iterator( + transforming_pair_iterator const&i, + typename boost::enable_if_convertible::type* = 0, + typename boost::enable_if_convertible::type* = 0, + typename boost::enable_if_convertible::type* = 0) + : Functor_base(i.functor()),iter1(i.iter1),iter2(i.iter2) {} + +}; + +template inline +transforming_pair_iterator make_transforming_pair_iterator(It1 i1, It2 i2, F const&f=F()) { + return transforming_pair_iterator(i1,i2,f); +} + +} + +#endif // CGAL_TRANSFORMING_PAIR_ITERATOR_H diff --git a/include/gudhi_patches/CGAL/typeset.h b/include/gudhi_patches/CGAL/typeset.h new file mode 100644 index 00000000..d4e24281 --- /dev/null +++ b/include/gudhi_patches/CGAL/typeset.h @@ -0,0 +1,117 @@ +// Copyright (c) 2014 +// INRIA Saclay-Ile de France (France) +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// Author(s) : Marc Glisse + +#ifndef CGAL_TYPESET_H +#define CGAL_TYPESET_H +#include +#ifdef CGAL_CXX11 +#include +#else +#include +#endif + +// Sometimes using tuple just to list types is overkill (takes forever to +// instantiate). + +namespace CGAL { +#ifdef CGAL_CXX11 + template struct typeset; + template struct typeset { + typedef H head; + typedef typeset tail; + typedef typeset type; + template using contains = typename + std::conditional< + std::is_same::value, + std::true_type, + typename tail::template contains + >::type; + template using add = typename + std::conditional< + contains::value, + typeset, + typeset + >::type; + }; + template<> struct typeset<> { + typedef typeset type; + template using contains = std::false_type; + template using add = typeset; + }; +#else + template struct typeset; + template, void, typeset >::type > + struct typeset { + typedef typeset type; + typedef H head; + typedef T tail; + template struct contains : + boost::mpl::if_,boost::true_type,typename tail::template contains >::type + {}; + template struct add; + //boost::mpl::if_,typeset,typeset >::type + }; + template<> struct typeset<> { + typedef typeset type; + template struct contains : boost::false_type {}; + template struct add : CGAL::typeset {}; + }; + + template + template + struct typeset::add : typeset::type> {}; + template + template + struct typeset::add : typeset {}; +#endif + + template struct typeset_union_ : + typeset_union_::type, typename T2::tail> + {}; + template struct typeset_union_ > : T {}; + + template + struct typeset_intersection_ { + typedef typename T1::head H; + typedef typename typeset_intersection_::type U; + typedef typename +#ifdef CGAL_CXX11 + std::conditional::value, +#else + boost::mpl::if_, +#endif + typename U::template add::type, U>::type type; + }; + template + struct typeset_intersection_,T> : typeset<> {}; + +#ifdef CGAL_CXX11 + template + using typeset_union = typename typeset_union_::type; + template + using typeset_intersection = typename typeset_intersection_::type; +#else + template + struct typeset_union : typeset_union_::type {}; + template + struct typeset_intersection : typeset_intersection_::type {}; +#endif +} +#endif diff --git a/include/gudhi_patches/Tangential_complex_CGAL_patches.txt b/include/gudhi_patches/Tangential_complex_CGAL_patches.txt new file mode 100644 index 00000000..5b9581a0 --- /dev/null +++ b/include/gudhi_patches/Tangential_complex_CGAL_patches.txt @@ -0,0 +1,82 @@ +CGAL/Regular_triangulation_traits_adapter.h +CGAL/Triangulation_ds_vertex.h +CGAL/Triangulation_data_structure.h +CGAL/transforming_pair_iterator.h +CGAL/NewKernel_d/static_int.h +CGAL/NewKernel_d/Cartesian_LA_functors.h +CGAL/NewKernel_d/Cartesian_change_FT.h +CGAL/NewKernel_d/Wrapper/Vector_d.h +CGAL/NewKernel_d/Wrapper/Hyperplane_d.h +CGAL/NewKernel_d/Wrapper/Ref_count_obj.h +CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h +CGAL/NewKernel_d/Wrapper/Point_d.h +CGAL/NewKernel_d/Wrapper/Segment_d.h +CGAL/NewKernel_d/Wrapper/Weighted_point_d.h +CGAL/NewKernel_d/Wrapper/Sphere_d.h +CGAL/NewKernel_d/Cartesian_per_dimension.h +CGAL/NewKernel_d/Kernel_object_converter.h +CGAL/NewKernel_d/KernelD_converter.h +CGAL/NewKernel_d/Vector/sse2.h +CGAL/NewKernel_d/Vector/avx4.h +CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h +CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h +CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h +CGAL/NewKernel_d/Vector/array.h +CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h +CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h +CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h +CGAL/NewKernel_d/Vector/vector.h +CGAL/NewKernel_d/Vector/v2int.h +CGAL/NewKernel_d/Vector/mix.h +CGAL/NewKernel_d/Cartesian_static_filters.h +CGAL/NewKernel_d/Cartesian_LA_base.h +CGAL/NewKernel_d/Lazy_cartesian.h +CGAL/NewKernel_d/Coaffine.h +CGAL/NewKernel_d/store_kernel.h +CGAL/NewKernel_d/Dimension_base.h +CGAL/NewKernel_d/Kernel_3_interface.h +CGAL/NewKernel_d/Cartesian_complete.h +CGAL/NewKernel_d/Cartesian_base.h +CGAL/NewKernel_d/Cartesian_filter_K.h +CGAL/NewKernel_d/functor_tags.h +CGAL/NewKernel_d/Filtered_predicate2.h +CGAL/NewKernel_d/functor_properties.h +CGAL/NewKernel_d/Define_kernel_types.h +CGAL/NewKernel_d/LA_eigen/LA.h +CGAL/NewKernel_d/LA_eigen/constructors.h +CGAL/NewKernel_d/Types/Aff_transformation.h +CGAL/NewKernel_d/Types/Sphere.h +CGAL/NewKernel_d/Types/Hyperplane.h +CGAL/NewKernel_d/Types/Line.h +CGAL/NewKernel_d/Types/Ray.h +CGAL/NewKernel_d/Types/Iso_box.h +CGAL/NewKernel_d/Types/Weighted_point.h +CGAL/NewKernel_d/Types/Segment.h +CGAL/NewKernel_d/Kernel_d_interface.h +CGAL/NewKernel_d/utils.h +CGAL/NewKernel_d/Kernel_2_interface.h +CGAL/NewKernel_d/Cartesian_filter_NT.h +CGAL/NewKernel_d/function_objects_cartesian.h +CGAL/Convex_hull.h +CGAL/Triangulation_ds_full_cell.h +CGAL/Regular_triangulation.h +CGAL/Epick_d.h +CGAL/transforming_iterator.h +CGAL/iterator_from_indices.h +CGAL/Delaunay_triangulation.h +CGAL/IO/Triangulation_off_ostream.h +CGAL/typeset.h +CGAL/Triangulation_full_cell.h +CGAL/Triangulation.h +CGAL/internal/Static_or_dynamic_array.h +CGAL/internal/Combination_enumerator.h +CGAL/internal/Triangulation/utilities.h +CGAL/internal/Triangulation/Triangulation_ds_iterators.h +CGAL/internal/Triangulation/Dummy_TDS.h +CGAL/argument_swaps.h +CGAL/Epeck_d.h +CGAL/determinant_of_vectors.h +CGAL/TDS_full_cell_default_storage_policy.h +CGAL/TDS_full_cell_mirror_storage_policy.h +CGAL/Triangulation_face.h +CGAL/Triangulation_vertex.h -- cgit v1.2.3