diff options
Diffstat (limited to 'src')
117 files changed, 23124 insertions, 25 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a831814..e26b2d25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") find_package(Boost REQUIRED COMPONENTS system filesystem program_options chrono timer date_time REQUIRED) if(NOT Boost_FOUND) - message(FATAL_ERROR "NOTICE: This demo requires Boost and will not be compiled.") + message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.") else() # For "make doxygen" @@ -47,6 +47,10 @@ else() if(CGAL_FOUND) message(STATUS "CGAL version: ${CGAL_VERSION}.") include( ${CGAL_USE_FILE} ) + + if (NOT CGAL_VERSION VERSION_LESS 4.8.0) + include_directories(BEFORE "include/gudhi_patches") + endif() endif() if(MSVC) @@ -110,6 +114,7 @@ else() add_subdirectory(example/Alpha_complex) add_subdirectory(example/Spatial_searching) add_subdirectory(example/Subsampling) + add_subdirectory(example/Tangential_complex) # data points generator add_subdirectory(data/points/generator) diff --git a/src/Doxyfile b/src/Doxyfile index 51950b3d..943869ad 100644 --- a/src/Doxyfile +++ b/src/Doxyfile @@ -847,7 +847,8 @@ IMAGE_PATH = doc/Skeleton_blocker/ \ doc/Witness_complex/ \ doc/Bitmap_cubical_complex/ \ doc/Subsampling/ \ - doc/Spatial_searching/ + doc/Spatial_searching/ \ + doc/Tangential_complex/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/src/GudhUI/model/Model.h b/src/GudhUI/model/Model.h index 77e37b6c..fc284cc6 100644 --- a/src/GudhUI/model/Model.h +++ b/src/GudhUI/model/Model.h @@ -187,7 +187,7 @@ class Model { } void contract_edges(unsigned num_contractions) { - Clock c; + Gudhi::Clock c; Edge_contractor<Complex> contractor(complex_, num_contractions); std::cout << "Time to simplify: " << c.num_seconds() << "s" << std::endl; } @@ -248,7 +248,7 @@ class Model { unsigned num_simplices = 0; int euler = 0; int dimension = 0; - Clock clock; + Gudhi::Clock clock; for (const auto &s : complex_.complex_simplex_range()) { num_simplices++; dimension = (std::max)(s.dimension(), dimension); @@ -271,7 +271,7 @@ class Model { #ifdef _WIN32 std::cout << "Works only on linux x64 for the moment\n"; #else - Clock clock; + Gudhi::Clock clock; run_chomp(); clock.end(); #endif diff --git a/src/Tangential_complex/benchmark/CMakeLists.txt b/src/Tangential_complex/benchmark/CMakeLists.txt new file mode 100644 index 00000000..12488201 --- /dev/null +++ b/src/Tangential_complex/benchmark/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 2.6) +project(Tangential_complex_benchmark) + +if (GCOVR_PATH) + # for gcovr to make coverage reports - Corbera Jenkins plugin + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif() +if (GPROF_PATH) + # for gprof to make coverage reports - Jenkins + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") +endif() + +# need CGAL 4.8 +if(CGAL_FOUND) + if (NOT CGAL_VERSION VERSION_LESS 4.8.0) + message(STATUS "CGAL version: ${CGAL_VERSION}.") + + find_package(Eigen3 3.1.0) + if (EIGEN3_FOUND) + message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.") + include( ${EIGEN3_USE_FILE} ) + + add_executable(Tangential_complex_benchmark benchmark_tc.cpp) + target_link_libraries(Tangential_complex_benchmark + ${Boost_DATE_TIME_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY}) + if (TBB_FOUND) + target_link_libraries(Tangential_complex_benchmark ${TBB_LIBRARIES}) + endif() + + # Do not forget to copy test files in current binary dir + #file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + + else() + message(WARNING "Eigen3 not found. Version 3.1.0 is required for Tangential complex feature.") + endif() + else() + message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile Tangential complex feature. Version 4.8.0 is required.") + endif () +endif() + diff --git a/src/Tangential_complex/benchmark/RIB_exporter.h b/src/Tangential_complex/benchmark/RIB_exporter.h new file mode 100644 index 00000000..73c14041 --- /dev/null +++ b/src/Tangential_complex/benchmark/RIB_exporter.h @@ -0,0 +1,269 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GUDHI_TC_RIB_EXPORTER_H +#define GUDHI_TC_RIB_EXPORTER_H + +#include <gudhi/Tangential_complex/utilities.h> + +#include <tuple> +#include <string> + +template <typename PointRandomAccessRange, typename SimplexRange> +class RIB_exporter { + typedef typename PointRandomAccessRange::value_type Point; + typedef typename SimplexRange::value_type Simplex; + public: + + typedef std::tuple<double, double, double, double> Color; // RGBA + typedef std::tuple<int, int, int> Coords_choice; + + // Constructor + RIB_exporter( + PointRandomAccessRange const& points, + SimplexRange const& simplices, + std::ofstream &out, + std::string const& rendered_image_filename = "export.tif", + bool is_preview = false, // low-quality + Coords_choice coords_choice = std::make_tuple(0, 1, 2), + int image_width = 1920, + int image_height = 1080, + Color const& triangle_color = std::make_tuple(1., 1., 1., 1.), + bool ambient_light = true, + double ambient_intensity = 0.3, + bool shadow = true, + double shadow_intensity = 0.85, + double point_sphere_radius = 0.003) + : m_points(points), + m_simplices(simplices), + m_out(out), + m_rendered_image_filename(rendered_image_filename), + m_is_preview(is_preview), + m_coords_choice(coords_choice), + m_image_width(image_width), + m_image_height(image_height), + m_current_color(0., 0., 0., 0.), + m_current_alpha(1), + m_triangle_color(triangle_color), + m_ambient_light(ambient_light), + m_ambient_intensity(ambient_intensity), + m_shadow(shadow), + m_shadow_intensity(shadow_intensity), + m_point_sphere_radius(point_sphere_radius) { + m_out.precision(8); + } + + void write_file() { + write_header(); + write_lights(); + /*if (m_point_sphere_radius != 0.) + write_point_spheres();*/ + write_triangles(); + + m_out << "WorldEnd\n"; + } + + private: + + void write_header() { + m_out << "Option \"searchpath\" \"shader\" " + "\".:./shaders:%PIXIE_SHADERS%:%PIXIEHOME%/shaders\"\n"; + + if (m_is_preview) { + m_out << "Attribute \"visibility\" \"specular\" 1\n" + << "Attribute \"visibility\" \"transmission\" 1\n\n"; + } + + m_out << "Display \"" << m_rendered_image_filename << "\" \"file\" \"rgb\"\n"; + + if (!m_is_preview) { + m_out << "Format " << m_image_width << " " << m_image_height << " 1\n"; + } else { + double ratio = double(m_image_height) / double(m_image_width); + + int width = (ratio < 1.) ? 300 : int(300. / ratio); + int height = (ratio < 1.) ? int(ratio * 300.) : 300; + + m_out << "Format " << width << " " << height << " 1\n"; + } + + + if (m_image_width > m_image_height) { + double ratio = double(m_image_height) / double(m_image_width); + m_out << "ScreenWindow -1 1 " << -ratio << " " << ratio << "\n"; + } else if (m_image_height > m_image_width) { + double ratio = double(m_image_width) / double(m_image_height); + m_out << "ScreenWindow " << -ratio << " " << ratio << " -1 1\n"; + } + + m_out << "Projection \"perspective\" \"fov\" 45\n" + << "Translate 0 0 3\n" + << "PixelSamples 4 4\n" + << "PixelFilter \"catmull-rom\" 3 3\n" + << "ShadingInterpolation \"smooth\"\n" + << "Rotate -10 20 0 1\n" + << "WorldBegin\n"; + } + + void write_lights() { + if (!m_is_preview) { + // ShadowLight + m_out << "LightSource \"shadowdistant\" 1 \"from\" [0 0 0] \"to\" [0 0 1]" + << " \"shadowname\" \"raytrace\" \"intensity\" " + << m_shadow_intensity << "\n"; + + // Ambient light + m_out << "LightSource \"ambientlight\" 2 \"intensity\" " + << m_ambient_intensity << "\n"; + } else { + m_out << "LightSource \"distantLight\" 1 \"from\" [0 0 0] \"to\" [0 0 1]" + << " \"intensity\" " << m_shadow_intensity << "\n"; + + // Ambient light + m_out << "LightSource \"ambientlight\" 2 \"intensity\" " + << m_ambient_intensity << "\n"; + } + + // Background light + m_out << "LightSource \"ambientlight\" 99 \"intensity\" 1\n"; + + // Turn background light OFF + turn_background_light(false); + } + + void turn_background_light(bool turn_on) { + if (!turn_on) { + m_out << "Illuminate 1 1" << std::endl; + if (!m_is_preview) + m_out << "Illuminate 2 1" << std::endl; + m_out << "Illuminate 99 0" << std::endl; + } else { + m_out << "Illuminate 1 0" << std::endl; + if (!m_is_preview) + m_out << "Illuminate 2 0" << std::endl; + m_out << "Illuminate 99 1" << std::endl; + } + } + + void write_color(Color const& color, bool use_transparency) { + if (m_current_color == color) + return; + + m_current_color = color; + + // Write opacity data + if (use_transparency) + write_opacity(std::get<3>(color)); + + // Write color data + m_out << "Color [ " << std::get<0>(color) << " " << std::get<1>(color) + << " " << std::get<2>(color) << " ]\n"; + } + + void write_opacity(const double alpha) { + if (m_current_alpha == alpha) + return; + + m_current_alpha = alpha; + + // Write opacity data + m_out << "Opacity " << alpha << " " << alpha << " " << alpha << std::endl; + } + + void write_point(Point const& p) { + m_out << " " << p[std::get<0>(m_coords_choice)] + << " " << p[std::get<1>(m_coords_choice)] + << " " << p[std::get<2>(m_coords_choice)] << " "; + } + + void write_triangles() { + m_out << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl; + + for (auto const& simplex : m_simplices) { + std::vector<Simplex> triangles; + // Get the triangles composing the simplex + combinations(simplex, 3, std::back_inserter(triangles)); + for (auto const& t : triangles) + write_triangle(t); + } + } + + template <typename PointIndexRange> + void write_triangle(PointIndexRange const& t) { + // Color + write_color(m_triangle_color, true); + + // Triangle + m_out << "Polygon \"P\" ["; + for (auto idx : t) + write_point(m_points[idx]); + m_out << "]" << std::endl; + + // Edges (will be drawn later on) + /*add_edge(p, q, edge_color); + add_edge(p, r, edge_color); + add_edge(q, r, edge_color); + + // Vertices (will be drawn later on) + add_vertex(p, edge_color); + add_vertex(q, edge_color); + add_vertex(r, edge_color);*/ + } + + void write_point_sphere(Point const& p) { + if (m_point_sphere_radius == 0.) + return; + + m_out << "Translate " << p[0] << " " << p[1] << " " << p[2] << std::endl; + // Sphere radius zmin zmax thetamax + m_out << "Sphere " << m_point_sphere_radius << " " << -m_point_sphere_radius + << " " << m_point_sphere_radius << " 360" << std::endl; + m_out << "Identity" << std::endl; + } + + void write_point_spheres() { + write_color(std::make_tuple(0.7, 0.7, 0.7, 0.5), true); + for (auto const& p : m_points) + write_point_sphere(p); + } + + //=========================================================================== + + PointRandomAccessRange const& m_points; + SimplexRange const& m_simplices; + std::ofstream &m_out; + std::string m_rendered_image_filename; + bool m_is_preview; + Coords_choice m_coords_choice; + int m_image_width; + int m_image_height; + Color m_current_color; + Color m_triangle_color; + double m_current_alpha; + bool m_ambient_light; + double m_ambient_intensity; + bool m_shadow; + double m_shadow_intensity; + double m_point_sphere_radius; +}; + +#endif // GUDHI_TC_RIB_EXPORTER_H diff --git a/src/Tangential_complex/benchmark/XML_exporter.h b/src/Tangential_complex/benchmark/XML_exporter.h new file mode 100644 index 00000000..ed44f90a --- /dev/null +++ b/src/Tangential_complex/benchmark/XML_exporter.h @@ -0,0 +1,207 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <string> +#include <vector> +#include <iostream> +#include <fstream> +#include <ctime> + +template<typename value_type = std::string> +class Simple_XML_exporter { + public: + typedef value_type Value_type; + typedef std::vector<value_type> Element; + typedef std::map<std::string, value_type> Element_with_map; + typedef std::vector<Element> List_of_elements; + + Simple_XML_exporter( + const std::string &list_name, + const std::string &element_name, + const std::vector<std::string> &subelement_names, + bool add_timestamp = true) + : m_list_name(list_name), + m_element_name(element_name), + m_subelement_names(subelement_names), + m_add_timestamp(add_timestamp) { } + + bool add_element(const Element &element) { + if (element.size() == m_subelement_names.size()) { + m_list_of_elements.push_back(element); + return true; + } else { + std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl; + return false; + } + } + + bool add_element(Element_with_map &element) { + Element elt; + + std::vector<std::string>::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector<std::string>::const_iterator + it_subelement_name_end = m_subelement_names.end(); + for (; it_subelement_name != it_subelement_name_end; ++it_subelement_name) { + elt.push_back(element[*it_subelement_name]); + } + + return add_element(elt); + } + + bool export_to_xml(const std::string &filename) const { + std::ofstream xmlfile; + xmlfile.open(filename.c_str()); + xmlfile << "<?xml version='1.0'?>" << std::endl; + xmlfile << "<" << m_list_name << ">" << std::endl; + + typename List_of_elements::const_iterator it_element = m_list_of_elements.begin(); + typename List_of_elements::const_iterator it_element_end = m_list_of_elements.end(); + for (int id = 1; it_element != it_element_end; ++it_element, ++id) { + xmlfile << " <" << m_element_name << ">" << std::endl; + std::vector<std::string>::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector<std::string>::const_iterator + it_subelement_name_end = m_subelement_names.end(); + + if (m_add_timestamp) + xmlfile << " <id> " << time(NULL) << " </id>" << std::endl; + + for (int i = 0; + it_subelement_name != it_subelement_name_end; + ++it_subelement_name, ++i) { + xmlfile + << " <" << *it_subelement_name << "> " + << (*it_element)[i] + << " </" << *it_subelement_name << ">" << std::endl; + } + xmlfile << " </" << m_element_name << ">" << std::endl; + } + + xmlfile << "</" << m_list_name << ">" << std::endl; + xmlfile.close(); + return 0; + + } + + protected: + std::string m_list_name; + std::string m_element_name; + std::vector<std::string> m_subelement_names; + List_of_elements m_list_of_elements; + bool m_add_timestamp; +}; + +template<typename value_type = std::string> +class Streaming_XML_exporter { + public: + typedef value_type Value_type; + typedef std::vector<value_type> Element; + typedef std::map<std::string, value_type> Element_with_map; + typedef std::vector<Element> List_of_elements; + + Streaming_XML_exporter( + const std::string &filename, + const std::string &list_name, + const std::string &element_name, + const std::vector<std::string> &subelement_names, + bool add_timestamp = true) + : m_list_name(list_name), + m_element_name(element_name), + m_subelement_names(subelement_names), + m_add_timestamp(add_timestamp) { + m_xml_fstream.open(filename.c_str()); + if (m_xml_fstream.good()) { + m_xml_fstream << "<?xml version='1.0'?>" << std::endl; + m_xml_fstream << "<" << m_list_name << ">" << std::endl; + } else { + std::cerr << "Could not open file '" << filename << "'." << std::endl; + } + } + + virtual ~Streaming_XML_exporter() { + close_file(); + } + + void close_file() { + m_xml_fstream.close(); + } + + bool add_element(const Element &element) { + if (element.size() == m_subelement_names.size()) { + m_xml_fstream << " <" << m_element_name << ">" << std::endl; + std::vector<std::string>::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector<std::string>::const_iterator + it_subelement_name_end = m_subelement_names.end(); + + if (m_add_timestamp) { + m_xml_fstream << " <id> " << time(NULL) << " </id>" << std::endl; + } + + for (int i = 0; + it_subelement_name != it_subelement_name_end; + ++it_subelement_name, ++i) { + m_xml_fstream + << " <" << *it_subelement_name << "> " + << element[i] + << " </" << *it_subelement_name << ">" << std::endl; + } + m_xml_fstream << " </" << m_element_name << ">" << std::endl; + + // Save current pointer position + std::ofstream::streampos pos = m_xml_fstream.tellp(); + // Close the XML file (temporarily) so that the XML file is always correct + m_xml_fstream << "</" << m_list_name << ">" << std::endl; + // Restore the pointer position so that the next "add_element" will overwrite + // the end of the file + m_xml_fstream.seekp(pos); + + m_xml_fstream.flush(); + return true; + } else { + std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl; + return false; + } + } + + bool add_element(Element_with_map &element) { + Element elt; + + std::vector<std::string>::const_iterator + it_subelement_name = m_subelement_names.begin(); + std::vector<std::string>::const_iterator + it_subelement_name_end = m_subelement_names.end(); + for (; it_subelement_name != it_subelement_name_end; ++it_subelement_name) { + elt.push_back(element[*it_subelement_name]); + } + + return add_element(elt); + } + + protected: + std::ofstream m_xml_fstream; + std::string m_list_name; + std::string m_element_name; + std::vector<std::string> m_subelement_names; + bool m_add_timestamp; +}; diff --git a/src/Tangential_complex/benchmark/benchmark_script.txt b/src/Tangential_complex/benchmark/benchmark_script.txt new file mode 100644 index 00000000..f4ddaac3 --- /dev/null +++ b/src/Tangential_complex/benchmark/benchmark_script.txt @@ -0,0 +1,221 @@ +#--------------------------------------------------------------------------------------------------------------------------------------------------------- +# Input PARAM1 PARAM2 PARAM3 NUM_P AMB INTR SPARSITY MAX_PERTURB PERTURB ADD_HDIM COLLAPSE FIX_TIME_LIMIT NUM_ITERATIONS +#--------------------------------------------------------------------------------------------------------------------------------------------------------- + +#---------------------------------------------------------------- Alpha TC tests ------------------------------------------------------------------------ +#generate_sphere_d 1 0 - 8 2 1 0.01 0.005 N Y N 3 1 #No noise => OK: 6 2d with a perturb sometimes +#generate_sphere_d 1 0 - 50 2 1 0.01 0.005 N Y N 3 1 #No noise => OK: 49 1d +#generate_sphere_d 1 1 - 50 2 1 0.01 0.005 N Y N 3 1 #Noise => OK: 45 2d + 3 3d +#generate_torus_d N - - 15 2 1 0.01 0.05 N Y N 10 1 +#generate_sphere_d 0.302 0 - 8 3 2 0.01 0.005 N Y N 60 1 #No noise => OK: 7 3d with a perturb sometimes +#generate_sphere_d 0.302 0 - 50 3 2 0.01 0.005 N Y N 60 1 #No noise => no inconsitencies +#generate_sphere_d 0.302 3 - 50 3 2 0.01 0.005 N Y N 60 1 #Noise => OK: 90 2d + 3 3d +#generate_sphere_d 1 1 - 500 4 3 0.01 0.005 N Y N 60 1 #Noise 1% => OK: 3113 3d + 35 4d +#generate_sphere_d 1 2 - 500 4 3 0.01 0.005 N Y N 60 1 #Noise 2% => OK: 2969 3d + 91 4d +#generate_sphere_d 1 2 - 5000 4 3 0.01 0.005 N Y N 60 1 #Noise 2% => OK: 27905 3d + 2485 4d +#generate_sphere_d 0.302 2 - 300 2 1 0.01 0.005 N Y N 60 1 +#generate_torus_3D 2 1 N 200 3 2 0.01 0.05 N Y N 600 1 #OK: 1048 3d ~170s +#generate_torus_3D 2 1 N 2000 3 2 0.01 0.05 N Y N 600 1 #OK: 3545 2d + 27 3d ~35s +#generate_torus_d N 1 - 50 4 2 0.01 0.05 N Y N 3 1 #OK: 431 4d +#generate_torus_d N 1 - 500 4 2 0.01 0.05 N Y N 3 1 #OK: 881 2d + 37 3d +#generate_torus_d Y 1 - 250 4 2 0.01 0.05 N Y N 3 1 #OK: 80 d2 + 185 d3 +#generate_torus_d N - - 50 6 3 0.01 0.05 Y Y N 10 1 # +#generate_torus_d Y - - 700 6 3 0.01 0.05 Y Y N 100 1 #Grid +#generate_torus_d N - - 10000 6 3 0.01 0.05 Y Y N 30000 1 +#generate_moment_curve 0 1 - 10 3 1 0.01 0.005 N Y N 60 1 +#generate_two_spheres_d 3 4 - 500 3 2 0.01 0.05 N Y N 10 1 #OK: 320 2d + 1167 3d +#generate_klein_bottle_4D 40 15 - 500 4 2 0.01 0.2 N Y N 60 1 #OK: 901 d2 + 50 d3 + 1 d4 +#data/SO3_10000.xyz - - - 0 9 3 0.01 0.05 Y Y N 300 1 #Too long. Be careful with the memory consumption! +#data/buddha_100kv.xyz - - - 0 3 2 0.01 0.005 Y Y N 120 1 #Too long... +#data/fandisk.xyz - - - 0 3 2 0.01 0.005 Y Y N 5 1 #NOT OK: Tq & V do not intersect + +#---------------------------------------------------------- Spatial search benchmarking -------------------------------------------------------------- +#generate_torus_3D 2 1 Y 10000 3 2 0 0 Y N N 600 1 +#data/buddha_100kv.xyz - - - 0 3 2 0 0 N Y N 120 1 +#generate_torus_d N - - 10000 30 15 0 0 Y N N 3600 1 +#generate_torus_d N - - 100000 12 6 0 0 Y N N 3600 1 +#data/SO3_50000.xyz - - - 0 9 3 0 0 Y N N 60 1 +#data/Cy8.xyz - - - 0 24 2 0 0 N Y N 60 1 +#generate_sphere_d 0.5 - - 10000 2 1 0 0 N N Y 60 1 +#generate_sphere_d 0.5 - - 10000 3 2 0 0 N N Y 60 1 +#generate_sphere_d 0.5 - - 10000 4 3 0 0 N N Y 60 1 +#generate_sphere_d 0.5 - - 10000 5 4 0 0 N N Y 60 1 +#generate_sphere_d 0.5 - - 10000 6 5 0 0 N N Y 60 1 +#generate_sphere_d 0.5 - - 10000 7 6 0 0 N N Y 60 1 + +#---------------------------------------------------------- Very small cases for Debug mode -------------------------------------------------------------- +#generate_sphere_d 4 - - 20 3 2 0.05 0.025 Y N N 60 1 +generate_sphere_d 3 10 - 70 3 2 0.05 0.025 Y N N 60 1 +#generate_sphere_d 3 - - 1000 3 2 0.05 0.025 Y N N 60 1 +#generate_sphere_d 3 - - 10 4 3 0.05 0.025 Y N N 60 1 +#generate_sphere_d 3 - - 70 5 4 0.05 0.025 Y N N 60 1 +#generate_klein_bottle_4D 4 3 - 70 4 2 0.05 0.025 Y N N 3 1 +#generate_klein_bottle_variant_5D 4 3 - 70 5 2 0.05 0.025 Y N N 3 1 +#data/SO3_10000.xyz - - - 0 9 3 0.7 0.35 Y N N 60 1 +#generate_moment_curve 0 1 - 30 3 1 0.005 0.0025 Y N N 60 1 + +#------------------------------------------------------------------ From files -------------------------------------------------------------------------- +#data/SO3_50000.xyz - - - 0 9 3 0.05 0.05 Y N N 6000 1 +#data/SO3_10000.xyz - - - 0 9 3 0.1 0.1 Y N N 60000 1 +#data/cube3D_eps_0.1.xyz - - - 0 3 2 0.05 0.05 Y N N 3000 1 +#data/cube4D_eps_0.1.xyz - - - 0 4 3 0.05 0.05 N Y N 3000 1 +#data/cube5D_eps_0.1.xyz - - - 0 5 4 0.05 0.05 N Y N 3000 1 +#data/Cy8.xyz - - - 0 24 2 0.1 0.1 N Y N 60 1 +#data/Kl.xyz - - - 0 5 2 0.05 0.05 N Y N 60 1 +#data/S3.xyz - - - 0 4 3 0.05 0.05 N Y N 60 1 + +#data/Alvarez_variete_k2_D4_29700p.xyz - - - 0 4 2 0.01 0.01 Y N N 60 1 # points on a "grid" +#data/Alvarez_variete_k2_D4_10k_1x1_v2.xyz - - - 0 4 2 0.001 0.001 Y N N 200 1 +#data/Alvarez_variete_k2_D4_30k_1x1_v2.xyz - - - 0 4 2 0.001 0.001 Y N N 6000 1 +#data/Alvarez_variete_k2_D4_120k_2x2_denser_in_1x1.xyz - - - 0 4 2 0.002 0.002 Y N N 60000 1 +#data/Alvarez_variete_k2_D4_300k_2x2.xyz - - - 0 4 2 0.005 0.005 Y N N 100000 1 +#data/Alvarez_variete_k2_D4_300k_2x2.xyz - - - 0 4 2 0.05 0.05 Y N N 50000 1 # heavy sparsification (e.g. 0.05 => 33k points) +#data/Alvarez_variete_k2_D4_90k_2x2.xyz - - - 0 4 2 0.003 0.003 Y N N 6000 1 +#data/Alvarez_variete_k2_D4_30k_10x10.xyz - - - 0 4 2 0.01 0.01 Y N N 60 1 +#data/Alvarez_variete_k2_D4_60k_10x10.xyz - - - 0 4 2 0.01 0.01 Y N N 1800 1 + +#data/Alvarez_variete_k2_D8_9003p.xyz - - - 0 8 2 0.001 0.001 Y N N 60 1 +#data/Alvarez_variete_k2_D8_90K.xyz - - - 0 8 2 0.001 0.001 Y N N 60 1 +#data/Alvarez_variete_k2_D8_300k_10x10.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 # heavy sparsification +#data/Alvarez_variete_k2_D8_900k_2x2.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 # heavy sparsification +#data/Alvarez_variete_k2_D8_900k_10x10.xyz - - - 0 8 2 0.02 0.02 Y N N 60 1 # heavy sparsification + +#data/Alvarez_courbeElliptique_k2_D8_200K_2x2.xyz - - - 0 8 2 0.006 0.006 Y N N 60 1 + +#data/Alvarez_surface_deg2_k2_D8_6000K_10x10.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.003 0.003 Y N N 3600 1 +#data/Alvarez_surface_deg4_k2_D8_382K.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 +#data/Alvarez_surface_deg5_k2_D8_112K.xyz - - - 0 8 2 0.001 0.001 Y N N 240 1 +#data/Alvarez_surface_deg6_k2_D8_67K.xyz - - - 0 8 2 0.015 0.015 Y N N 60 1 +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 +#data/Alvarez_surface_deg8_k2_D8_41K.xyz - - - 0 8 2 0.025 0.025 Y N N 60 1 +#data/Alvarez_surface_deg9_k2_D8_42K.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 +#data/Alvarez_surface_deg10_k2_D8_41K.xyz - - - 0 8 2 0.01 0.01 Y N N 60 1 + +#data/Alvarez_surface_deg8_k2_D8_41K.xyz - - - 0 8 2 0.02 0.02 Y N N 600 1 +#data/sparsified/Alvarez_deg8_k2_D8_32K_sparsified_from_41K_0.01.xyz - - - 0 8 2 0.05 0.05 Y N N 600 1 + +# PAS VRAIMENT DE DIFFERENCE +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.003 0.007 Y N N 3600 1 +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.014 0.007 Y N N 3600 1 + +# PAS VRAIMENT DE DIFFERENCE +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.01 0.005 Y N N 120 1 +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.02 0.005 Y N N 120 1 + +# PAS VRAIMENT DE DIFFERENCE +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.001 0.01 Y N N 3600 1 +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.02 0.01 Y N N 3600 1 +#data/sparsified/Alvarez_deg3_k2_D8_534k_sparsified_from_902K_0.001.xyz - - - 0 8 2 0.01 0.01 Y N N 3600 1 + +# PAS TRES CLAIR, MAIS DIFFERENCE EN NOMBRE D'ETAPES (>100 vs 15-20) : +#data/sparsified/Alvarez_deg8_k2_D8_38K_sparsified_from_41K_0.005.xyz - - - 0 8 2 0.02 0.02 Y N N 600 1 +#data/Alvarez_surface_deg8_k2_D8_41K.xyz - - - 0 8 2 0.001 0.02 Y N N 60 1 +#data/Alvarez_surface_deg8_k2_D8_41K.xyz - - - 0 8 2 0.025 0.02 Y N N 60 1 + +# With pre-computed tangent spaces +#data/test.pwt - - - 0 4 2 0.01 0.01 N N N 500000 1 +#data/Alvarez_variete_k2_D4_30000p.xyz - - - 0 4 2 0.01 0.01 Y N N 500000 1 +#data/Alvarez_variete_k2_D4_30000p_with_TSB.pwt - - - 0 4 2 0.01 0.01 Y N N 500000 1 + +#---------------------------------------------------------------------- 3D meshes ----------------------------------------------------------------------- +#data/buddha_100kv.xyz - - - 0 3 2 0.005 0.005 Y N N 3 1 +#data/fandisk.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#data/fertility.xyz - - - 0 3 2 0.4 0.4 Y N N 3 1 +#data/bunny.xyz - - - 0 3 2 0.0006 0.0003 Y N N 3000 1 +#data/blob.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#data/3holes.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#data/785_hand_2500v.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#data/785_hand_50kv.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#data/bumpy_sphere.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#D:\INRIA\Data\_Models\Pointclouds\ajax_jotero.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#D:\INRIA\Data\_Models\Pointclouds\house.xyz - - - 0 3 2 0.01 0.01 Y N N 3 1 +#D:\INRIA\Data\_Models\Pointclouds\lucy_14M.xyz - - - 0 3 2 0.6 0.3 Y N N 3 1 + +#----------------------------------------------------------- Generated point sets ----------------------------------------------------------------------- +#generate_sphere_d 3 - - 4 3 2 0.05 0.05 Y N N 3000 1 +#generate_sphere_d 3 - - 30000 2 1 0.005 0.005 Y N N 3000 1 +#generate_sphere_d 1 - - 500000 3 2 0.005 0.005 Y N N 3000 1 +#generate_sphere_d 3 - - 30000 4 3 0.05 0.05 Y N N 3000 1 +#generate_sphere_d 3 0 - 300 3 2 0.005 0.005 Y N N 60 1 +#generate_sphere_d 3 4 - 3000 3 2 0.005 0.005 Y N N 60 1 +#generate_sphere_d 3 7 - 3000 3 2 0.005 0.005 Y N N 60 1 +#generate_torus_3D 2 1 N 300 3 2 0.05 0.05 Y N N 600 1 +#generate_torus_d N - - 200 4 2 0.05 0.05 Y N N 600 1 + +#generate_torus_d Y - - 100 6 3 0.1 0.19 Y N N 600 1 +#generate_torus_d Y - - 1000 6 3 0. 0.19 Y N N 600 1 +#generate_torus_d Y - - 10000 6 3 0. 0.19 Y N N 600 1 +#generate_torus_d Y - - 100000 6 3 0. 0.19 Y N N 600 1 +#generate_plane - - - 30000 3 2 0.005 0.005 Y N N 3000 1 +#generate_moment_curve 0 1 - 30000 6 1 0.005 0.005 Y N N 60 1 +#generate_klein_bottle_4D 4 3 - 700 4 2 0.05 0.05 Y N N 500 20 +#generate_klein_bottle_variant_5D 4 3 - 30000 5 2 0.05 0.05 Y N N 600 1 +#generate_klein_bottle_4D 8 5 - 5000 4 2 0.2 0.2 Y N N 60 1 #Takes forever +#data/sparsified/Flat_torus_195p_sparsified_0.05_from_200p.xyz N - - 0 4 2 -1 0.2 Y N N 600 1 + +#----------------------------------------------------------- Performance testing ------------------------------------------------------------------------ +# TC: 5.55 / 1st fix step : 0.2 +#data/fertility.xyz - - - 0 3 2 0.1 0.1 Y N N 10 1 + +#---------------------------------------------------------- 04/04/2016 - for stats ---------------------------------------------------------- + +#generate_torus_3D 2 1 N 5000 3 2 0.05 0.05 Y N N 120 1 +#generate_torus_d N - - 500 4 2 0.05 0.05 Y N N 120 1 +#data/Alvarez_variete_k2_D8_900k_2x2.xyz - - - 0 8 2 0.005 0.005 Y N N 120 1 +#data/Alvarez_surface_deg3_k2_D8_902K.xyz - - - 0 8 2 0.01 0.01 Y N N 120 1 +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.02 0.02 Y N N 600 10 +#data/Alvarez_surface_deg8_k2_D8_41K.xyz - - - 0 8 2 0.02 0.02 Y N N 120 1 +#data/Alvarez_surface_deg10_k2_D8_41K.xyz - - - 0 8 2 0.02 0.02 Y N N 120 1 +#generate_torus_d N - - 200000 6 3 0.05 0.05 Y N N 1200 1 + +#---------------------------------------------------------- 14/04/2016 - stats about noise ---------------------------------------------------------- + +#generate_torus_d Y 0 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 1 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 2 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 3 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 4 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 5 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 6 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 7 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 8 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 9 - 1000 4 2 0.05 0.19 Y N N 120 4 +#generate_torus_d Y 10 - 1000 4 2 0.05 0.19 Y N N 120 4 + +#generate_sphere_d 3 0 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 1 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 2 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 3 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 4 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 5 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 6 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 7 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 8 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 9 - 1000 4 3 0.05 0.05 Y N N 120 4 +#generate_sphere_d 3 10 - 1000 4 3 0.05 0.05 Y N N 120 4 + +#generate_klein_bottle_4D 4 3 0 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.01 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.02 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.03 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.04 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.05 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.06 5000 4 2 0.05 0.05 Y N N 120 4 +#generate_klein_bottle_4D 4 3 0.07 5000 4 2 0.05 0.05 Y N N 120 4 + +#---------------------------------------------------------- 04/2016 - stats with different perturb techniques ---------------------------------------------------------- + +# Tangential translation +#data/SO3_50000.xyz - - - 0 9 3 0 0.05 Y N N 500 10 +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.02 0.01 Y N N 120 10 +#generate_klein_bottle_4D 4 3 0 5000 4 2 0.05 0.05 Y N N 120 10 +#generate_torus_d Y 0 - 1000 4 2 0.05 0.19 Y N N 120 10 +#generate_sphere_d 3 1 - 1000 4 3 0.05 0.05 Y N N 120 10 + +# Weight +#data/SO3_50000.xyz - - - 0 9 3 0.1 0.05 Y N N 500 10 +#data/Alvarez_surface_deg7_k2_D8_48K.xyz - - - 0 8 2 0.02 0.01 Y N N 120 10 +#generate_klein_bottle_4D 4 3 0 5000 4 2 0.05 0.025 Y N N 20000 10 +#generate_torus_d Y 0 - 1000 4 2 0.05 0.025 Y N N 120 10 +#generate_sphere_d 3 1 - 1000 4 3 0.05 0.025 Y N N 12000 10
\ No newline at end of file diff --git a/src/Tangential_complex/benchmark/benchmark_tc.cpp b/src/Tangential_complex/benchmark/benchmark_tc.cpp new file mode 100644 index 00000000..943fcb54 --- /dev/null +++ b/src/Tangential_complex/benchmark/benchmark_tc.cpp @@ -0,0 +1,785 @@ +/****************************************************************************** +This benchmark allows to compute the Tangential Complex from input files or +generated point sets. + +It reads the benchmark_script.txt file (located in the same folder as this +file) and compute one or several complexes for each line. Unless TC_NO_EXPORT +is defined, each complex is exported as an OFF file and/or as a RIB file +(RenderMan). In addition an XML file is created at each run of the benchmark. +It contains statistics about the complexes that were created. This XML file +can be processed in Excel, for example. + ******************************************************************************/ + +// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB +// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/) +#ifdef _DEBUG +#define TBB_USE_THREADING_TOOL +#endif + +#include <cstddef> + +//#define GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM +//#define TC_INPUT_STRIDES 3 // only take one point every TC_INPUT_STRIDES points +#define TC_NO_EXPORT // do not output OFF files +//#define TC_EXPORT_TO_RIB // +//#define GUDHI_TC_EXPORT_SPARSIFIED_POINT_SET +//#define GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF + +const std::size_t ONLY_LOAD_THE_FIRST_N_POINTS = 20000000; + +#include <gudhi/Debug_utils.h> +#include <gudhi/Clock.h> +#include <gudhi/Tangential_complex.h> +#include <gudhi/sparsify_point_set.h> +#include <gudhi/random_point_generators.h> +#include <gudhi/Tangential_complex/utilities.h> + +#include <CGAL/assertions_behaviour.h> +#include <CGAL/Epick_d.h> +#include <CGAL/Random.h> + +#include <boost/algorithm/string/replace.hpp> +#include <boost/algorithm/string/trim_all.hpp> +#include <boost/range/adaptor/strided.hpp> + +#include <cstdlib> +#include <ctime> +#include <fstream> +#include <cmath> // for std::sqrt + +#ifdef GUDHI_USE_TBB +#include <tbb/task_scheduler_init.h> +#endif +#include "XML_exporter.h" +#include "RIB_exporter.h" +#define GUDHI_TC_EXPORT_PERFORMANCE_DATA +#define GUDHI_TC_SET_PERFORMANCE_DATA(value_name, value) \ + XML_perf_data::set(value_name, value); + + +namespace subsampl = Gudhi::subsampling; +namespace tc = Gudhi::tangential_complex; + +const char * const BENCHMARK_SCRIPT_FILENAME = "benchmark_script.txt"; + +typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_d Point; +typedef Kernel::Vector_d Vector; +typedef tc::Tangential_complex< +Kernel, CGAL::Dynamic_dimension_tag, +CGAL::Parallel_tag> TC; +typedef TC::Simplex Simplex; +typedef TC::Simplex_set Simplex_set; + +class XML_perf_data { + public: + typedef Streaming_XML_exporter<std::string> XML_exporter; + + XML_perf_data(const std::string &filename) + : m_xml(filename, "ContainerPerformance", "Perf", + construct_subelements_names()) { } + + virtual ~XML_perf_data() { } + + static XML_perf_data &get() { + static XML_perf_data singleton(build_filename()); + return singleton; + } + + template <typename Value_type> + static void set(const std::string &name, Value_type value) { + get().set_data(name, value); + } + + static void commit() { + get().commit_current_element(); + } + + protected: + + static std::string build_filename() { + std::stringstream sstr; + sstr << "perf_logs/Performance_log_" << time(0) << ".xml"; + return sstr.str(); + } + + static std::vector<std::string> construct_subelements_names() { + std::vector<std::string> subelements; + subelements.push_back("Input"); + subelements.push_back("Param1"); + subelements.push_back("Param2"); + subelements.push_back("Param3"); + subelements.push_back("Intrinsic_dim"); + subelements.push_back("Ambient_dim"); + subelements.push_back("Num_threads"); + subelements.push_back("Sparsity"); + subelements.push_back("Max_perturb"); + subelements.push_back("Num_points_in_input"); + subelements.push_back("Num_points"); + subelements.push_back("Perturb_technique"); + subelements.push_back("Perturb_which_points"); + subelements.push_back("Initial_num_inconsistent_local_tr"); + subelements.push_back("Best_num_inconsistent_local_tr"); + subelements.push_back("Final_num_inconsistent_local_tr"); + subelements.push_back("Init_time"); + subelements.push_back("Comput_time"); + subelements.push_back("Perturb_successful"); + subelements.push_back("Perturb_time"); + subelements.push_back("Perturb_steps"); + subelements.push_back("Result_pure_pseudomanifold"); + subelements.push_back("Result_num_wrong_dim_simplices"); + subelements.push_back("Result_num_wrong_number_of_cofaces"); + subelements.push_back("Result_num_unconnected_stars"); + subelements.push_back("Info"); + + return subelements; + } + + void set_data(const std::string &name, const std::string &value) { + m_current_element[name] = value; + } + + template <typename Value_type> + void set_data(const std::string &name, Value_type value) { + std::stringstream sstr; + sstr << value; + set_data(name, sstr.str()); + } + + void commit_current_element() { + m_xml.add_element(m_current_element); + m_current_element.clear(); + } + + XML_exporter m_xml; + XML_exporter::Element_with_map m_current_element; +}; + +template< +typename Kernel, typename OutputIteratorPoints> +bool load_points_from_file( + const std::string &filename, + OutputIteratorPoints points, + std::size_t only_first_n_points = std::numeric_limits<std::size_t>::max()) { + typedef typename Kernel::Point_d Point; + + std::ifstream in(filename); + if (!in.is_open()) { + std::cerr << "Could not open '" << filename << "'" << std::endl; + return false; + } + + Kernel k; + Point p; + int num_ppints; + in >> num_ppints; + + std::size_t i = 0; + while (i < only_first_n_points && in >> p) { + *points++ = p; + ++i; + } + +#ifdef DEBUG_TRACES + std::cerr << "'" << filename << "' loaded." << std::endl; +#endif + + return true; +} + +template< +typename Kernel, typename Tangent_space_basis, +typename OutputIteratorPoints, typename OutputIteratorTS> +bool load_points_and_tangent_space_basis_from_file( + const std::string &filename, + OutputIteratorPoints points, + OutputIteratorTS tangent_spaces, + int intrinsic_dim, + std::size_t only_first_n_points = std::numeric_limits<std::size_t>::max()) { + typedef typename Kernel::Point_d Point; + typedef typename Kernel::Vector_d Vector; + + std::ifstream in(filename); + if (!in.is_open()) { + std::cerr << "Could not open '" << filename << "'" << std::endl; + return false; + } + + Kernel k; + Point p; + int num_ppints; + in >> num_ppints; + + std::size_t i = 0; + while (i < only_first_n_points && in >> p) { + *points++ = p; + + Tangent_space_basis tsb(i); + for (int d = 0; d < intrinsic_dim; ++d) { + Vector v; + in >> v; + tsb.push_back(tc::internal::normalize_vector(v, k)); + } + *tangent_spaces++ = tsb; + ++i; + } + +#ifdef DEBUG_TRACES + std::cerr << "'" << filename << "' loaded." << std::endl; +#endif + + return true; +} + +// color_inconsistencies: only works if p_complex = NULL +template <typename TC> +bool export_to_off( + TC const& tc, + std::string const& input_name_stripped, + std::string const& suffix, + bool color_inconsistencies = false, + typename TC::Simplicial_complex const* p_complex = NULL, + 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) { +#ifdef TC_NO_EXPORT + return true; +#endif + + CGAL::Identity<Point> proj_functor; + + if (tc.intrinsic_dimension() <= 3) { + std::stringstream output_filename; + output_filename << "output/" << input_name_stripped << "_" + << tc.intrinsic_dimension() << "_in_R" + << tc.ambient_dimension() << "_" + << tc.number_of_vertices() << "v" + << suffix << ".off"; + std::ofstream off_stream(output_filename.str().c_str()); + + if (p_complex) { +#ifndef TC_NO_EXPORT + tc.export_to_off( + *p_complex, off_stream, + p_simpl_to_color_in_red, + p_simpl_to_color_in_green, + p_simpl_to_color_in_blue, + proj_functor); +#endif + } else { + tc.export_to_off( + off_stream, color_inconsistencies, + p_simpl_to_color_in_red, + p_simpl_to_color_in_green, + p_simpl_to_color_in_blue, + NULL, + proj_functor); + } + return true; + } + return false; +} + +void make_tc(std::vector<Point> &points, + TC::TS_container const& tangent_spaces, // can be empty + int intrinsic_dim, + double sparsity = 0.01, + double max_perturb = 0.005, + bool perturb = true, + bool add_high_dim_simpl = false, + bool collapse = false, + double time_limit_for_perturb = 0., + const char *input_name = "tc") { + Kernel k; + + if (sparsity > 0. && !tangent_spaces.empty()) { + std::cerr << "Error: cannot sparsify point set with pre-computed normals.\n"; + return; + } + + //=========================================================================== + // Init + //=========================================================================== + Gudhi::Clock t; + + // Get input_name_stripped + std::string input_name_stripped(input_name); + size_t slash_index = input_name_stripped.find_last_of('/'); + if (slash_index == std::string::npos) + slash_index = input_name_stripped.find_last_of('\\'); + if (slash_index == std::string::npos) + slash_index = 0; + else + ++slash_index; + input_name_stripped = input_name_stripped.substr( + slash_index, input_name_stripped.find_last_of('.') - slash_index); + + GUDHI_TC_SET_PERFORMANCE_DATA("Num_points_in_input", points.size()); + +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + std::vector<Point> points_not_sparse = points; +#endif + + //=========================================================================== + // Sparsify point set if requested + //=========================================================================== + if (sparsity > 0.) { + std::size_t num_points_before = points.size(); + std::vector<Point> sparsified_points; + subsampl::sparsify_point_set(k, points, sparsity*sparsity, + std::back_inserter(sparsified_points)); + sparsified_points.swap(points); + std::cerr << "Number of points before/after sparsification: " + << num_points_before << " / " << points.size() << "\n"; + +#ifdef GUDHI_TC_EXPORT_SPARSIFIED_POINT_SET + std::ofstream ps_stream("output/sparsified_point_set.txt"); + tc::internal::export_point_set(k, points, ps_stream); +#endif + } + + GUDHI_TC_SET_PERFORMANCE_DATA("Sparsity", sparsity); + GUDHI_TC_SET_PERFORMANCE_DATA("Max_perturb", max_perturb); + GUDHI_TC_SET_PERFORMANCE_DATA("Num_points", points.size()); + + //=========================================================================== + // Compute Tangential Complex + //=========================================================================== + + TC tc( + points, + intrinsic_dim, +#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM + points_not_sparse.begin(), points_not_sparse.end(), +#endif + k); + + if (!tangent_spaces.empty()) { + tc.set_tangent_planes(tangent_spaces); + } + + t.end(); + double init_time = t.num_seconds(); + + t.begin(); + tc.compute_tangential_complex(); + t.end(); + double computation_time = t.num_seconds(); + + //=========================================================================== + // Export to OFF + //=========================================================================== + + // Create complex + int max_dim = -1; + TC::Simplicial_complex complex; + Simplex_set inconsistent_simplices; + max_dim = tc.create_complex(complex, true, false, 2, &inconsistent_simplices); + + // TODO(CJ): TEST + Gudhi::Simplex_tree<> stree; + tc.create_complex(stree, true, false); + // std::cerr << stree; + + t.begin(); + bool ret = export_to_off( + tc, input_name_stripped, "_INITIAL_TC", true, + &complex, &inconsistent_simplices); + t.end(); + double export_before_time = (ret ? t.num_seconds() : -1); + + unsigned int num_perturb_steps = 0; + double perturb_time = -1; + double export_after_perturb_time = -1.; + bool perturb_success = false; + if (perturb) { + //========================================================================= + // Try to fix inconsistencies by perturbing points + //========================================================================= + t.begin(); + auto fix_result = + tc.fix_inconsistencies_using_perturbation(max_perturb, time_limit_for_perturb); + t.end(); + perturb_time = t.num_seconds(); + + perturb_success = fix_result.success; + GUDHI_TC_SET_PERFORMANCE_DATA("Initial_num_inconsistent_local_tr", + fix_result.initial_num_inconsistent_stars); + GUDHI_TC_SET_PERFORMANCE_DATA("Best_num_inconsistent_local_tr", + fix_result.best_num_inconsistent_stars); + GUDHI_TC_SET_PERFORMANCE_DATA("Final_num_inconsistent_local_tr", + fix_result.final_num_inconsistent_stars); + + //========================================================================= + // Export to OFF + //========================================================================= + + // Re-build the complex + Simplex_set inconsistent_simplices; + max_dim = tc.create_complex(complex, true, false, 2, &inconsistent_simplices); + + t.begin(); + bool exported = export_to_off( + tc, input_name_stripped, "_AFTER_FIX", true, &complex, + &inconsistent_simplices); + t.end(); + export_after_perturb_time = (exported ? t.num_seconds() : -1); + + //std::string fn = "output/inc_stars/"; + //fn += input_name_stripped; + //tc.export_inconsistent_stars_to_OFF_files(fn); + +#if !defined(TC_NO_EXPORT) && defined(TC_EXPORT_TO_RIB) + std::ofstream rib(std::string("output/") + input_name_stripped + ".rib"); + RIB_exporter<TC::Points, TC::Simplicial_complex::Simplex_set> rib_exporter( + tc.points(), + complex.simplex_range(), + rib, + input_name_stripped + ".tif", + false, // is_preview + std::make_tuple(2, 4, 6), + 1600, 503 // resolution + ); + rib_exporter.write_file(); + + std::ofstream rib_LQ(std::string("output/") + input_name_stripped + "_LQ.rib"); + RIB_exporter<TC::Points, TC::Simplicial_complex::Simplex_set> rib_exporter_LQ( + tc.points(), + complex.simplex_range(), + rib_LQ, + input_name_stripped + "_LQ.tif", + true, // is_preview + std::make_tuple(0, 4, 5) + ); + rib_exporter_LQ.write_file(); +#endif + } else { + GUDHI_TC_SET_PERFORMANCE_DATA("Initial_num_inconsistent_local_tr", "N/A"); + GUDHI_TC_SET_PERFORMANCE_DATA("Best_num_inconsistent_local_tr", "N/A"); + GUDHI_TC_SET_PERFORMANCE_DATA("Final_num_inconsistent_local_tr", "N/A"); + } + + max_dim = tc.create_complex(complex, true, false, 2); + + complex.display_stats(); + + if (intrinsic_dim == 2) + complex.euler_characteristic(true); + + //=========================================================================== + // Collapse + //=========================================================================== + if (collapse) { + complex.collapse(max_dim); + complex.display_stats(); + } + + //=========================================================================== + // Is the result a pure pseudomanifold? + //=========================================================================== + std::size_t num_wrong_dim_simplices, + num_wrong_number_of_cofaces, + num_unconnected_stars; + Simplex_set wrong_dim_simplices; + Simplex_set wrong_number_of_cofaces_simplices; + Simplex_set unconnected_stars_simplices; + bool is_pure_pseudomanifold = complex.is_pure_pseudomanifold( + intrinsic_dim, tc.number_of_vertices(), + false, // do NOT allow borders + false, 1, + &num_wrong_dim_simplices, &num_wrong_number_of_cofaces, + &num_unconnected_stars, + &wrong_dim_simplices, &wrong_number_of_cofaces_simplices, + &unconnected_stars_simplices); + + //=========================================================================== + // Export to OFF + //=========================================================================== + + double export_after_collapse_time = -1.; + if (collapse) { + t.begin(); + bool exported = export_to_off( + tc, input_name_stripped, "_AFTER_COLLAPSE", false, &complex, + &wrong_dim_simplices, &wrong_number_of_cofaces_simplices, + &unconnected_stars_simplices); + t.end(); + std::cerr + << " OFF colors:\n" + << " * Red: wrong dim simplices\n" + << " * Green: wrong number of cofaces simplices\n" + << " * Blue: not-connected stars\n"; + export_after_collapse_time = (exported ? t.num_seconds() : -1.); + } + + //=========================================================================== + // Display info + //=========================================================================== + + std::cerr + << "\n================================================\n" + << "Number of vertices: " << tc.number_of_vertices() << "\n" + << "Computation times (seconds): \n" + << " * Tangential complex: " << init_time + computation_time << "\n" + << " - Init + kd-tree = " << init_time << "\n" + << " - TC computation = " << computation_time << "\n" + << " * Export to OFF (before perturb): " << export_before_time << "\n" + << " * Fix inconsistencies 1: " << perturb_time + << " (" << num_perturb_steps << " steps) ==> " + << (perturb_success ? "FIXED" : "NOT fixed") << "\n" + << " * Export to OFF (after perturb): " << export_after_perturb_time << "\n" + << " * Export to OFF (after collapse): " + << export_after_collapse_time << "\n" + << "================================================\n"; + + //=========================================================================== + // Export info + //=========================================================================== + GUDHI_TC_SET_PERFORMANCE_DATA("Init_time", init_time); + GUDHI_TC_SET_PERFORMANCE_DATA("Comput_time", computation_time); + GUDHI_TC_SET_PERFORMANCE_DATA("Perturb_successful", + (perturb_success ? 1 : 0)); + GUDHI_TC_SET_PERFORMANCE_DATA("Perturb_time", perturb_time); + GUDHI_TC_SET_PERFORMANCE_DATA("Perturb_steps", num_perturb_steps); + GUDHI_TC_SET_PERFORMANCE_DATA("Result_pure_pseudomanifold", + (is_pure_pseudomanifold ? 1 : 0)); + GUDHI_TC_SET_PERFORMANCE_DATA("Result_num_wrong_dim_simplices", + num_wrong_dim_simplices); + GUDHI_TC_SET_PERFORMANCE_DATA("Result_num_wrong_number_of_cofaces", + num_wrong_number_of_cofaces); + GUDHI_TC_SET_PERFORMANCE_DATA("Result_num_unconnected_stars", + num_unconnected_stars); + GUDHI_TC_SET_PERFORMANCE_DATA("Info", ""); +} + +int main() { + CGAL::set_error_behaviour(CGAL::ABORT); + +#ifdef GUDHI_USE_TBB +#ifdef _DEBUG + int num_threads = 1; +#else + int num_threads = tbb::task_scheduler_init::default_num_threads() - 4; +#endif +#endif + + unsigned int seed = static_cast<unsigned int> (time(NULL)); + CGAL::default_random = CGAL::Random(seed); // TODO(CJ): use set_default_random + std::cerr << "Random seed = " << seed << "\n"; + + std::ifstream script_file; + script_file.open(BENCHMARK_SCRIPT_FILENAME); + // Script? + // Script file format: each line gives + // - Filename (point set) or "generate_XXX" (point set generation) + // - Ambient dim + // - Intrinsic dim + // - Number of iterations with these parameters + if (script_file.is_open()) { + int i = 1; +#ifdef GUDHI_USE_TBB +#ifdef BENCHMARK_WITH_1_TO_MAX_THREADS + for (num_threads = 1; + num_threads <= tbb::task_scheduler_init::default_num_threads(); + ++num_threads) +#endif +#endif + /*for (Concurrent_mesher_config::get().num_work_items_per_batch = 5 ; + Concurrent_mesher_config::get().num_work_items_per_batch < 100 ; + Concurrent_mesher_config::get().num_work_items_per_batch += 5)*/ { +#ifdef GUDHI_USE_TBB + tbb::task_scheduler_init init( + num_threads > 0 ? num_threads : tbb::task_scheduler_init::automatic); +#endif + + std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' found.\n"; + script_file.seekg(0); + while (script_file.good()) { + std::string line; + std::getline(script_file, line); + if (line.size() > 1 && line[0] != '#') { + boost::replace_all(line, "\t", " "); + boost::trim_all(line); + std::cerr << "\n\n"; + std::cerr << "*****************************************\n"; + std::cerr << "******* " << line << "\n"; + std::cerr << "*****************************************\n"; + std::stringstream sstr(line); + + std::string input; + std::string param1; + std::string param2; + std::string param3; + std::size_t num_points; + int ambient_dim; + int intrinsic_dim; + double sparsity; + double max_perturb; + char perturb, add_high_dim_simpl, collapse; + double time_limit_for_perturb; + int num_iteration; + sstr >> input; + sstr >> param1; + sstr >> param2; + sstr >> param3; + sstr >> num_points; + sstr >> ambient_dim; + sstr >> intrinsic_dim; + sstr >> sparsity; + sstr >> max_perturb; + sstr >> perturb; + sstr >> add_high_dim_simpl; + sstr >> collapse; + sstr >> time_limit_for_perturb; + sstr >> num_iteration; + + for (int j = 0; j < num_iteration; ++j) { + std::string input_stripped = input; + size_t slash_index = input_stripped.find_last_of('/'); + if (slash_index == std::string::npos) + slash_index = input_stripped.find_last_of('\\'); + if (slash_index == std::string::npos) + slash_index = 0; + else + ++slash_index; + input_stripped = input_stripped.substr( + slash_index, input_stripped.find_last_of('.') - slash_index); + + GUDHI_TC_SET_PERFORMANCE_DATA("Input", input_stripped); + GUDHI_TC_SET_PERFORMANCE_DATA("Param1", param1); + GUDHI_TC_SET_PERFORMANCE_DATA("Param2", param2); + GUDHI_TC_SET_PERFORMANCE_DATA("Param3", param3); + GUDHI_TC_SET_PERFORMANCE_DATA("Ambient_dim", ambient_dim); + GUDHI_TC_SET_PERFORMANCE_DATA("Intrinsic_dim", intrinsic_dim); + GUDHI_TC_SET_PERFORMANCE_DATA("Perturb_technique", "Tangential_translation"); + GUDHI_TC_SET_PERFORMANCE_DATA("Perturb_which_points", "Center_vertex"); + +#ifdef GUDHI_USE_TBB + GUDHI_TC_SET_PERFORMANCE_DATA( + "Num_threads", + (num_threads == -1 ? tbb::task_scheduler_init::default_num_threads() : num_threads)); +#else + GUDHI_TC_SET_PERFORMANCE_DATA("Num_threads", "N/A"); +#endif + + std::cerr << "\nTC #" << i << "...\n"; + +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t_gen; +#endif + + std::vector<Point> points; + TC::TS_container tangent_spaces; + + if (input == "generate_moment_curve") { + points = Gudhi::generate_points_on_moment_curve<Kernel>( + num_points, ambient_dim, + std::atof(param1.c_str()), std::atof(param2.c_str())); + } else if (input == "generate_plane") { + points = Gudhi::generate_points_on_plane<Kernel>( + num_points, intrinsic_dim, ambient_dim); + } else if (input == "generate_sphere_d") { + points = Gudhi::generate_points_on_sphere_d<Kernel>( + num_points, ambient_dim, + std::atof(param1.c_str()), // radius + std::atof(param2.c_str())); // radius_noise_percentage + } else if (input == "generate_two_spheres_d") { + points = Gudhi::generate_points_on_two_spheres_d<Kernel>( + num_points, ambient_dim, + std::atof(param1.c_str()), + std::atof(param2.c_str()), + std::atof(param3.c_str())); + } else if (input == "generate_3sphere_and_circle_d") { + GUDHI_CHECK(intrinsic_dim == 3, + std::logic_error("Intrinsic dim should be 3")); + GUDHI_CHECK(ambient_dim == 5, + std::logic_error("Ambient dim should be 5")); + points = Gudhi::generate_points_on_3sphere_and_circle<Kernel>( + num_points, + std::atof(param1.c_str())); + } else if (input == "generate_torus_3D") { + points = Gudhi::generate_points_on_torus_3D<Kernel>( + num_points, + std::atof(param1.c_str()), + std::atof(param2.c_str()), + param3 == "Y"); + } else if (input == "generate_torus_d") { + points = Gudhi::generate_points_on_torus_d<Kernel>( + num_points, + intrinsic_dim, + param1 == "Y", // uniform + std::atof(param2.c_str())); // radius_noise_percentage + } else if (input == "generate_klein_bottle_3D") { + points = Gudhi::generate_points_on_klein_bottle_3D<Kernel>( + num_points, + std::atof(param1.c_str()), std::atof(param2.c_str())); + } else if (input == "generate_klein_bottle_4D") { + points = Gudhi::generate_points_on_klein_bottle_4D<Kernel>( + num_points, + std::atof(param1.c_str()), std::atof(param2.c_str()), + std::atof(param3.c_str())); // noise + } else if (input == "generate_klein_bottle_variant_5D") { + points = Gudhi::generate_points_on_klein_bottle_variant_5D<Kernel>( + num_points, + std::atof(param1.c_str()), std::atof(param2.c_str())); + } else { + // Contains tangent space basis + if (input.substr(input.size() - 3) == "pwt") { + load_points_and_tangent_space_basis_from_file + <Kernel, typename TC::Tangent_space_basis > ( + input, std::back_inserter(points), + std::back_inserter(tangent_spaces), + intrinsic_dim, + ONLY_LOAD_THE_FIRST_N_POINTS); + } else { + load_points_from_file<Kernel>( + input, std::back_inserter(points), + ONLY_LOAD_THE_FIRST_N_POINTS); + } + } + +#ifdef GUDHI_TC_PROFILING + t_gen.end(); + std::cerr << "Point set generated/loaded in " << t_gen.num_seconds() + << " seconds.\n"; +#endif + + if (!points.empty()) { +#if defined(TC_INPUT_STRIDES) && TC_INPUT_STRIDES > 1 + auto p = points | boost::adaptors::strided(TC_INPUT_STRIDES); + std::vector<Point> points(p.begin(), p.end()); + std::cerr << "****************************************\n" + << "WARNING: taking 1 point every " << TC_INPUT_STRIDES + << " points.\n" + << "****************************************\n"; +#endif + + make_tc(points, tangent_spaces, intrinsic_dim, + sparsity, max_perturb, + perturb == 'Y', add_high_dim_simpl == 'Y', collapse == 'Y', + time_limit_for_perturb, input.c_str()); + + std::cerr << "TC #" << i++ << " done.\n"; + std::cerr << "\n---------------------------------\n"; + } else { + std::cerr << "TC #" << i++ << ": no points loaded.\n"; + } + + XML_perf_data::commit(); + } + } + } + script_file.seekg(0); + script_file.clear(); + } + + script_file.close(); + } // Or not script? + else { + std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' NOT found.\n"; + } + + // system("pause"); + return 0; +} diff --git a/src/Tangential_complex/doc/Intro_tangential_complex.h b/src/Tangential_complex/doc/Intro_tangential_complex.h new file mode 100644 index 00000000..3d687c1d --- /dev/null +++ b/src/Tangential_complex/doc/Intro_tangential_complex.h @@ -0,0 +1,119 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef DOC_TANGENTIAL_COMPLEX_INTRO_TANGENTIAL_COMPLEX_H_ +#define DOC_TANGENTIAL_COMPLEX_INTRO_TANGENTIAL_COMPLEX_H_ + +// needs namespaces for Doxygen to link on classes +namespace Gudhi { +namespace tangential_complex { + +/** \defgroup tangential_complex Tangential complex + +\author Clément Jamin + +@{ + +\section tangentialdefinition Definition + +A Tangential Delaunay complex is a <a target="_blank" href="https://en.wikipedia.org/wiki/Simplicial_complex">simplicial complex</a> +designed to reconstruct a \f$k\f$-dimensional smooth manifold embedded in \f$d\f$-dimensional Euclidean space. +The input is a point sample coming from an unknown manifold, which means that the points lie close to a structure of "small" intrinsic dimension. +The running time depends only linearly on the extrinsic dimension \f$ d \f$ +and exponentially on the intrinsic dimension \f$ k \f$. + +An extensive description of the Tangential complex can be found in \cite tangentialcomplex2014. + +\subsection whatisthetc What is a Tangential Complex? + +Let us start with the description of the Tangential complex of a simple example, with \f$ k=1 \f$ and \f$ d=2 \f$. +The input data is 4 points \f$ P \f$ located on a curve embedded in 2D. +\image html "tc_example_01.png" "The input" +For each point \f$ p \f$, estimate its tangent subspace \f$ T_p \f$ (e.g. using PCA). +\image html "tc_example_02.png" "The estimated normals" +Let us add the Voronoi diagram of the points in orange. For each point \f$ p \f$, construct its star in the Delaunay triangulation of \f$ P \f$ restricted to \f$ T_p \f$. +\image html "tc_example_03.png" "The Voronoi diagram" +The Tangential Delaunay complex is the union of those stars. + +In practice, neither the ambient Voronoi diagram nor the ambient Delaunay triangulation is computed. +Instead, local \f$ k \f$-dimensional regular triangulations are computed with a limited number of points as we only need the star of each point. +More details can be found in \cite tangentialcomplex2014. + +\subsection inconsistencies Inconsistencies + +Inconsistencies between the stars can occur. +An inconsistency occurs when a simplex is not in the star of all its vertices. + +Let us take the same example. +\image html "tc_example_07_before.png" "Before" +Let us slightly move the tangent subspace \f$ T_q \f$ +\image html "tc_example_07_after.png" "After" +Now, the star of \f$ Q \f$ contains \f$ QP \f$, but the star of \f$ P \f$ does not contain \f$ QP \f$. We have an inconsistency. +\image html "tc_example_08.png" "After" + +One way to solve inconsistencies is to randomly perturb the positions of the points involved in an inconsistency. +In the current implementation, this perturbation is done in the tangent subspace of each point. +The maximum perturbation radius is given as a parameter to the constructor. + +In most cases, we recommend to provide a point set where the minimum distance between any two points +is not too small. This can be achieved using the functions provided by the Subsampling module. Then, a good value to start with for +the maximum perturbation radius would be around half the minimum distance between any two points. +The \ref example_with_perturb below shows an example of such a process. + +In most cases, this process is able to dramatically reduce the number of inconsistencies, but is not guaranteed to succeed. + +\subsection output Output + +The result of the computation is exported as a `Simplex_tree`. It is the union of the stars of all the input points. +A vertex in the Simplex Tree is the index of the point in the range provided by the user. +The point corresponding to a vertex can also be obtained through the `Tangential_complex::get_point` function. +Note that even if the positions of the points are perturbed, their original positions are kept (e.g. `Tangential_complex::get_point` returns the original position of the point). + +The result can be obtained after the computation of the Tangential complex itself and/or after the perturbation process. + +\section simple_example Simple example + +This example builds the Tangential complex of point set. +Note that the dimension of the kernel here is dynamic, which is slower, but more flexible: +the intrinsic and ambient dimensions does not have to be known at compile-time. + +\include Tangential_complex/example_basic.cpp + +\section example_with_perturb Example with perturbation + +This example builds the Tangential complex of a point set, then tries to solve inconsistencies +by perturbing the positions of points involved in inconsistent simplices. +Note that the dimension of the kernel here is static, which is the best choice when the +dimensions are known at compile-time. + +\include Tangential_complex/example_with_perturb.cpp + +\copyright GNU General Public License v3. +\verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim + */ +/** @} */ // end defgroup tangential_complex + +} // namespace tangential_complex + +} // namespace Gudhi + +#endif // DOC_TANGENTIAL_COMPLEX_INTRO_TANGENTIAL_COMPLEX_H_ diff --git a/src/Tangential_complex/doc/tc_example_01.png b/src/Tangential_complex/doc/tc_example_01.png Binary files differnew file mode 100644 index 00000000..8afe6198 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_01.png diff --git a/src/Tangential_complex/doc/tc_example_02.png b/src/Tangential_complex/doc/tc_example_02.png Binary files differnew file mode 100644 index 00000000..01591c1d --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_02.png diff --git a/src/Tangential_complex/doc/tc_example_03.png b/src/Tangential_complex/doc/tc_example_03.png Binary files differnew file mode 100644 index 00000000..5de04e01 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_03.png diff --git a/src/Tangential_complex/doc/tc_example_05.png b/src/Tangential_complex/doc/tc_example_05.png Binary files differnew file mode 100644 index 00000000..fdd5e5fa --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_05.png diff --git a/src/Tangential_complex/doc/tc_example_06.png b/src/Tangential_complex/doc/tc_example_06.png Binary files differnew file mode 100644 index 00000000..31ad3c43 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_06.png diff --git a/src/Tangential_complex/doc/tc_example_07.png b/src/Tangential_complex/doc/tc_example_07.png Binary files differnew file mode 100644 index 00000000..47e34de7 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_07.png diff --git a/src/Tangential_complex/doc/tc_example_07_after.png b/src/Tangential_complex/doc/tc_example_07_after.png Binary files differnew file mode 100644 index 00000000..981350d2 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_07_after.png diff --git a/src/Tangential_complex/doc/tc_example_07_before.png b/src/Tangential_complex/doc/tc_example_07_before.png Binary files differnew file mode 100644 index 00000000..ddc6bc7b --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_07_before.png diff --git a/src/Tangential_complex/doc/tc_example_08.png b/src/Tangential_complex/doc/tc_example_08.png Binary files differnew file mode 100644 index 00000000..119a87de --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_08.png diff --git a/src/Tangential_complex/doc/tc_example_09.png b/src/Tangential_complex/doc/tc_example_09.png Binary files differnew file mode 100644 index 00000000..31bac1e0 --- /dev/null +++ b/src/Tangential_complex/doc/tc_example_09.png diff --git a/src/Tangential_complex/doc/tc_examples.png b/src/Tangential_complex/doc/tc_examples.png Binary files differnew file mode 100644 index 00000000..b6544afe --- /dev/null +++ b/src/Tangential_complex/doc/tc_examples.png diff --git a/src/Tangential_complex/example/CMakeLists.txt b/src/Tangential_complex/example/CMakeLists.txt new file mode 100644 index 00000000..7ba043f0 --- /dev/null +++ b/src/Tangential_complex/example/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 2.6) +project(Tangential_complex_examples) + +if(CGAL_FOUND) + if (NOT CGAL_VERSION VERSION_LESS 4.8.0) + message(STATUS "CGAL version: ${CGAL_VERSION}.") + + find_package(Eigen3 3.1.0) + if (EIGEN3_FOUND) + message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.") + include( ${EIGEN3_USE_FILE} ) + include_directories (BEFORE "../../include") + + add_executable( Tangential_complex_example_basic example_basic.cpp ) + target_link_libraries(Tangential_complex_example_basic ${CGAL_LIBRARY} ${Boost_DATE_TIME_LIBRARY}) + add_executable( Tangential_complex_example_with_perturb example_with_perturb.cpp ) + target_link_libraries(Tangential_complex_example_with_perturb ${CGAL_LIBRARY} ${Boost_DATE_TIME_LIBRARY}) + if (TBB_FOUND) + target_link_libraries(Tangential_complex_example_basic ${TBB_LIBRARIES}) + target_link_libraries(Tangential_complex_example_with_perturb ${TBB_LIBRARIES}) + endif() + else() + message(WARNING "Eigen3 not found. Version 3.1.0 is required for the Tangential_complex examples.") + endif() + else() + message(WARNING "CGAL version: ${CGAL_VERSION} is too old to compile Tangential_complex examples. Version 4.8.0 is required.") + endif () +else() + message(WARNING "CGAL not found. It is required for the Tangential_complex examples.") +endif() diff --git a/src/Tangential_complex/example/example_basic.cpp b/src/Tangential_complex/example/example_basic.cpp new file mode 100644 index 00000000..4f2b859e --- /dev/null +++ b/src/Tangential_complex/example/example_basic.cpp @@ -0,0 +1,46 @@ +#include <gudhi/Tangential_complex.h> +#include <gudhi/sparsify_point_set.h> + +#include <CGAL/Epick_d.h> +#include <CGAL/Random.h> + +#include <array> +#include <vector> + +namespace tc = Gudhi::tangential_complex; + +typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_d Point; +typedef Kernel::Vector_d Vector; +typedef tc::Tangential_complex< +Kernel, CGAL::Dynamic_dimension_tag, +CGAL::Parallel_tag> TC; + +int main(void) { + const int INTRINSIC_DIM = 2; + const int AMBIENT_DIM = 3; + const int NUM_POINTS = 1000; + + Kernel k; + + // Generate points on a 2-sphere + CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.); + std::vector<Point> points; + points.reserve(NUM_POINTS); + for (int i = 0; i < NUM_POINTS; ++i) + points.push_back(*generator++); + + // Compute the TC + TC tc(points, INTRINSIC_DIM, k); + tc.compute_tangential_complex(); + + // Export the TC into a Simplex_tree + Gudhi::Simplex_tree<> stree; + tc.create_complex(stree); + + // Display stats about inconsistencies + tc.number_of_inconsistent_simplices(true); // verbose + + return 0; +} diff --git a/src/Tangential_complex/example/example_with_perturb.cpp b/src/Tangential_complex/example/example_with_perturb.cpp new file mode 100644 index 00000000..d0d877ea --- /dev/null +++ b/src/Tangential_complex/example/example_with_perturb.cpp @@ -0,0 +1,53 @@ +#include <gudhi/Tangential_complex.h> +#include <gudhi/sparsify_point_set.h> + +#include <CGAL/Epick_d.h> +#include <CGAL/Random.h> + +#include <array> +#include <vector> + +namespace subsampl = Gudhi::subsampling; +namespace tc = Gudhi::tangential_complex; + +typedef CGAL::Epick_d<CGAL::Dimension_tag < 3 >> Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_d Point; +typedef Kernel::Vector_d Vector; +typedef tc::Tangential_complex< +Kernel, CGAL::Dimension_tag<2>, +CGAL::Parallel_tag> TC; + +int main(void) { + const int INTRINSIC_DIM = 2; + const int AMBIENT_DIM = 3; + const int NUM_POINTS = 50; + + Kernel k; + + // Generate points on a 2-sphere + CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.); + std::vector<Point> points; + points.reserve(NUM_POINTS); + for (int i = 0; i < NUM_POINTS; ++i) + points.push_back(*generator++); + + // Sparsify the point set + std::vector<Point> sparsified_points; + subsampl::sparsify_point_set(k, points, 0.1 * 0.1, + std::back_inserter(sparsified_points)); + sparsified_points.swap(points); + + // Compute the TC + TC tc(points, INTRINSIC_DIM, k); + tc.compute_tangential_complex(); + + // Try to fix inconsistencies. Give it 10 seconds to succeed + tc.fix_inconsistencies_using_perturbation(0.05, 10); + + // Export the TC into a Simplex_tree + Gudhi::Simplex_tree<> stree; + tc.create_complex(stree); + + return 0; +} diff --git a/src/Tangential_complex/include/gudhi/Tangential_complex.h b/src/Tangential_complex/include/gudhi/Tangential_complex.h new file mode 100644 index 00000000..7cf5c498 --- /dev/null +++ b/src/Tangential_complex/include/gudhi/Tangential_complex.h @@ -0,0 +1,2277 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef TANGENTIAL_COMPLEX_H_ +#define TANGENTIAL_COMPLEX_H_ + +#include <gudhi/Tangential_complex/config.h> +#include <gudhi/Tangential_complex/Simplicial_complex.h> +#include <gudhi/Tangential_complex/utilities.h> +#include <gudhi/Kd_tree_search.h> +#include <gudhi/console_color.h> +#include <gudhi/Clock.h> +#include <gudhi/Simplex_tree.h> + +#include <CGAL/Default.h> +#include <CGAL/Dimension.h> +#include <CGAL/function_objects.h> // for CGAL::Identity +#include <CGAL/Epick_d.h> +#include <CGAL/Regular_triangulation_traits_adapter.h> +#include <CGAL/Regular_triangulation.h> +#include <CGAL/Delaunay_triangulation.h> +#include <CGAL/Combination_enumerator.h> +#include <CGAL/point_generators_d.h> + +#include <Eigen/Core> +#include <Eigen/Eigen> + +#include <boost/optional.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/range/adaptor/transformed.hpp> +#include <boost/range/counting_range.hpp> +#include <boost/math/special_functions/factorials.hpp> +#include <boost/container/flat_set.hpp> + +#include <tuple> +#include <vector> +#include <set> +#include <utility> +#include <sstream> +#include <iostream> +#include <limits> +#include <algorithm> +#include <functional> +#include <iterator> +#include <cmath> // for std::sqrt +#include <string> + +#ifdef GUDHI_USE_TBB +#include <tbb/parallel_for.h> +#include <tbb/combinable.h> +#include <tbb/mutex.h> +#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<std::size_t>::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 <a target="_blank" + * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> 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 <a target="_blank" + * href="http://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Dimension__tag.html">Dimension_tag<d></a> + * if you know the intrinsic dimension at compile-time, + * or <a target="_blank" + * href="http://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Dynamic__dimension__tag.html">CGAL::Dynamic_dimension_tag</a> + * 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<DimensionTag>, + CGAL::Triangulation_data_structure + < + typename CGAL::Epick_d<DimensionTag>::Dimension, + CGAL::Triangulation_vertex<CGAL::Regular_triangulation_traits_adapter< + CGAL::Epick_d<DimensionTag> >, Vertex_data >, + CGAL::Triangulation_full_cell<CGAL::Regular_triangulation_traits_adapter< + CGAL::Epick_d<DimensionTag> > > + > + > + >::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<Atomic_wrapper<FT> > Weights; +#else + typedef Vector Translation_for_perturb; + typedef std::vector<FT> Weights; +#endif + typedef std::vector<Translation_for_perturb> 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<K> Tangent_space_basis; + typedef Basis<K> Orthogonal_space_basis; + typedef std::vector<Tangent_space_basis> TS_container; + typedef std::vector<Orthogonal_space_basis> OS_container; + + typedef std::vector<Point> Points; + + typedef boost::container::flat_set<std::size_t> Simplex; + typedef std::set<Simplex> Simplex_set; + + private: + typedef sps::Kd_tree_search<K, Points> Points_ds; + typedef typename Points_ds::KNS_range KNS_range; + typedef typename Points_ds::INS_range INS_range; + + typedef std::vector<Tr_and_VH> Tr_container; + typedef std::vector<Vector> Vectors; + + // An Incident_simplex is the list of the vertex indices + // except the center vertex + typedef boost::container::flat_set<std::size_t> Incident_simplex; + typedef std::vector<Incident_simplex> Star; + typedef std::vector<Star> Stars_container; + + // For transform_iterator + + static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) { + return vh->point(); + } + + template <typename P, typename VH> + 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 <typename Point_range> + 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<Concurrency_tag, CGAL::Parallel_tag>::value) { + tbb::parallel_for(tbb::blocked_range<size_t>(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<std::size_t, std::size_t, std::size_t> 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<std::size_t> updated_points; + +#ifdef GUDHI_TC_PROFILING + Gudhi::Clock t_fix_step; +#endif + + // Parallel +#if defined(GUDHI_USE_TBB) + if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) { + tbb::combinable<std::size_t> num_inconsistencies; + tbb::combinable<std::vector<std::size_t> > tls_updated_points; + tbb::parallel_for( + tbb::blocked_range<size_t>(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<std::size_t>()); + updated_points = tls_updated_points.combine( + [](std::vector<std::size_t> const& x, + std::vector<std::size_t> const& y) { + std::vector<std::size_t> 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<std::size_t, std::size_t, std::size_t> 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 <typename Simplex_tree_> + 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<int> (c.size()) > max_dim) + max_dim = static_cast<int> (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<int> (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<int> (c.size()) > max_dim) + max_dim = static_cast<int> (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<typename ProjectionFunctor = CGAL::Identity<Point> > + 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<typename ProjectionFunctor = CGAL::Identity<Point> > + 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<Concurrency_tag, CGAL::Parallel_tag>::value) { + tbb::parallel_for(tbb::blocked_range<size_t>(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 <typename Point_indices_range> + 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<Concurrency_tag, CGAL::Parallel_tag>::value) { + tbb::parallel_for(tbb::blocked_range<size_t>(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<size_t>& 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<size_t>& 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<std::size_t>::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<FT> 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()) { +#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<Tr_full_cell_handle> incident_cells; + triangulation.incident_full_cells( + center_vertex, + std::back_inserter(incident_cells)); + for (typename std::vector<Tr_full_cell_handle>::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<Tr_point, + Tr_vertex_handle>), + boost::make_transform_iterator(cell->vertices_end(), + vertex_handle_to_point<Tr_point, + Tr_vertex_handle>)); + + 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<Tr_full_cell_handle> incident_cells; + local_tr.incident_full_cells( + center_vertex, std::back_inserter(incident_cells)); + + typename std::vector<Tr_full_cell_handle>::const_iterator it_c = incident_cells.begin(); + typename std::vector<Tr_full_cell_handle>::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); + } + 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 = static_cast<unsigned int> (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)); + + // 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(); + +#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<Eigen::MatrixXd> 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 = static_cast<unsigned int> (std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)); + + // 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<Eigen::MatrixXd> 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<FT> 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<int> (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<FT> coords; + // Ambiant-space coords of the projected point + std::vector<FT> 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<int> (coords.size()), coords.begin(), coords.end()), + w - sq_dist_to_proj_pt); + } + + // Project all the points in the tangent space + + template <typename Indexed_point_range> + std::vector<Tr_point> project_points_and_compute_weights( + const Indexed_point_range &point_indices, + const Tangent_space_basis &tsb, + const Tr_traits &tr_traits) const { + std::vector<Tr_point> 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<std::size_t>::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 <typename OutputIterator> // 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<std::size_t>::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<std::size_t> &m_num_inconsistencies; + tbb::combinable<std::vector<std::size_t> > &m_updated_points; + + public: + // Constructor + Try_to_solve_inconsistencies_in_a_local_triangulation(Tangential_complex &tc, + double max_perturb, + tbb::combinable<std::size_t> &num_inconsistencies, + tbb::combinable<std::vector<std::size_t> > &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<size_t>& 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_bare_point> + 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 <typename OutputIt> + 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<Point> 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<typename ProjectionFunctor = CGAL::Identity<Point> > + 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 == NULL || 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<std::pair<Simplex, int> > 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<bool> 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<Simplex> Triangles; + Triangles triangles; + + std::size_t num_vertices = 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<bool> 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<bool> 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<FT> 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/src/Tangential_complex/include/gudhi/Tangential_complex/Simplicial_complex.h b/src/Tangential_complex/include/gudhi/Tangential_complex/Simplicial_complex.h new file mode 100644 index 00000000..65c74ca5 --- /dev/null +++ b/src/Tangential_complex/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 <http://www.gnu.org/licenses/>. + */ + +#ifndef TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_ +#define TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_ + +#include <gudhi/Tangential_complex/config.h> +#include <gudhi/Tangential_complex/utilities.h> +#include <gudhi/Debug_utils.h> +#include <gudhi/console_color.h> + +#include <CGAL/iterator.h> + +// For is_pure_pseudomanifold +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> +#include <boost/container/flat_set.hpp> + +#include <algorithm> +#include <string> +#include <fstream> +#include <map> // for map<> +#include <vector> // for vector<> +#include <set> // for set<> + +namespace Gudhi { +namespace tangential_complex { +namespace internal { + +class Simplicial_complex { + public: + typedef boost::container::flat_set<std::size_t> Simplex; + typedef std::set<Simplex> 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<int> (s.size()); + std::vector<Complex::iterator> 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<Complex::iterator>::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 <typename Test, typename Output_it> + 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> Simplex_iterator_list; + typedef std::map<Simplex, Simplex_iterator_list> 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<int> (it_simplex->size()) > k + 1) { + std::vector<Simplex> 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<Simplex> 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<int, std::size_t> 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<int> (it_simplex->size()) - 1]; + } + + for (std::map<int, std::size_t>::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<K_1_face, std::size_t> 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<int> (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_face> 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 <int K> + 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<std::vector<Complex::const_iterator> > 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<int> (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<Simplex, std::vector<std::size_t> > + 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<std::size_t> dm1_simpl_of_link_vec( + dm1_simpl_of_link.begin(), dm1_simpl_of_link.end()); + + CGAL::Combination_enumerator<int> 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<Graph_vertex> 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<std::size_t>::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<int> 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<Complex::const_iterator>::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<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph; + // map that gives to a certain simplex its node in graph and its dimension + typedef boost::graph_traits<Adj_graph>::vertex_descriptor Graph_vertex; + typedef boost::graph_traits<Adj_graph>::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/src/Tangential_complex/include/gudhi/Tangential_complex/config.h b/src/Tangential_complex/include/gudhi/Tangential_complex/config.h new file mode 100644 index 00000000..98a1b14f --- /dev/null +++ b/src/Tangential_complex/include/gudhi/Tangential_complex/config.h @@ -0,0 +1,44 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef TANGENTIAL_COMPLEX_CONFIG_H_ +#define TANGENTIAL_COMPLEX_CONFIG_H_ + +#include <cstddef> + +// ========================= Debugging & profiling ============================= +#define GUDHI_TC_PROFILING +#define DEBUG_TRACES +// #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/src/Tangential_complex/include/gudhi/Tangential_complex/utilities.h b/src/Tangential_complex/include/gudhi/Tangential_complex/utilities.h new file mode 100644 index 00000000..b2d6d674 --- /dev/null +++ b/src/Tangential_complex/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 <http://www.gnu.org/licenses/>. + */ + +#ifndef TANGENTIAL_COMPLEX_UTILITIES_H_ +#define TANGENTIAL_COMPLEX_UTILITIES_H_ + +#include <CGAL/Dimension.h> +#include <CGAL/Combination_enumerator.h> +#include <CGAL/IO/Triangulation_off_ostream.h> + +#include <boost/container/flat_set.hpp> + +#include <Eigen/Core> +#include <Eigen/Eigen> + +#include <set> +#include <vector> +#include <array> +#include <fstream> +#include <atomic> +#include <cmath> // 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 <typename T> +struct Atomic_wrapper +: public std::atomic<T> { + typedef std::atomic<T> Base; + + Atomic_wrapper() { } + + Atomic_wrapper(const T &t) : Base(t) { } + + Atomic_wrapper(const std::atomic<T> &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<T> &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> +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<typename Kernel> +struct Basis { + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_d Point; + typedef typename Kernel::Vector_d Vector; + typedef typename std::vector<Vector>::const_iterator const_iterator; + + std::size_t m_origin; + std::vector<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<Vector>& vectors) + : m_origin(origin), m_vectors(vectors) { } + + int dimension() const { + return static_cast<int> (m_vectors.size()); + } +}; + +// 1st line: number of points +// Then one point per line +template <typename Kernel, typename Point_range> +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<std::size_t> +template <typename Elements_container, typename Output_iterator> +void combinations(const Elements_container elements, int k, + Output_iterator combinations) { + std::size_t n = elements.size(); + std::vector<bool> booleans(n, false); + std::fill(booleans.begin() + n - k, booleans.end(), true); + do { + boost::container::flat_set<std::size_t> 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/src/Tangential_complex/test/CMakeLists.txt b/src/Tangential_complex/test/CMakeLists.txt new file mode 100644 index 00000000..075028c8 --- /dev/null +++ b/src/Tangential_complex/test/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.6) +project(Tangential_complex_tests) + +if (GCOVR_PATH) + # for gcovr to make coverage reports - Corbera Jenkins plugin + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif() +if (GPROF_PATH) + # for gprof to make coverage reports - Jenkins + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") +endif() + +if(CGAL_FOUND) + if (NOT CGAL_VERSION VERSION_LESS 4.8.0) + if (EIGEN3_FOUND) + message(STATUS "Eigen3 version: ${EIGEN3_VERSION}.") + include( ${EIGEN3_USE_FILE} ) + include_directories (BEFORE "../../include") + + add_executable( Tangential_complex_test_TC test_tangential_complex.cpp ) + target_link_libraries(Tangential_complex_test_TC ${CGAL_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) + if (TBB_FOUND) + target_link_libraries(Tangential_complex_test_TC ${TBB_LIBRARIES}) + endif() + add_test(Tangential_complex_test_TC ${CMAKE_CURRENT_BINARY_DIR}/Tangential_complex_test_TC + # XML format for Jenkins xUnit plugin + --log_format=XML --log_sink=${CMAKE_SOURCE_DIR}/Tangential_complex_UT.xml --log_level=test_suite --report_level=no) + + endif() + endif () +endif()
\ No newline at end of file diff --git a/src/Tangential_complex/test/test_tangential_complex.cpp b/src/Tangential_complex/test/test_tangential_complex.cpp new file mode 100644 index 00000000..f8b0d2fb --- /dev/null +++ b/src/Tangential_complex/test/test_tangential_complex.cpp @@ -0,0 +1,70 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE Tangential_complex - test tangential complex +#include <boost/test/unit_test.hpp> + +#include <gudhi/Tangential_complex.h> +#include <gudhi/sparsify_point_set.h> + +#include <CGAL/Epick_d.h> +#include <CGAL/Random.h> + +#include <array> +#include <vector> + +namespace tc = Gudhi::tangential_complex; + +BOOST_AUTO_TEST_CASE(test_Spatial_tree_data_structure) { + typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel; + typedef Kernel::Point_d Point; + typedef tc::Tangential_complex< + Kernel, CGAL::Dynamic_dimension_tag, + CGAL::Parallel_tag> TC; + + const int INTRINSIC_DIM = 2; + const int AMBIENT_DIM = 3; + const int NUM_POINTS = 50; + + Kernel k; + + // Generate points on a 2-sphere + CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.); + std::vector<Point> points; + points.reserve(NUM_POINTS); + for (int i = 0; i < NUM_POINTS; ++i) + points.push_back(*generator++); + + // Compute the TC + TC tc(points, INTRINSIC_DIM, k); + tc.compute_tangential_complex(); + + // Try to fix inconsistencies. Give it 60 seconds to succeed + auto perturb_ret = tc.fix_inconsistencies_using_perturbation(0.01, 60); + + BOOST_CHECK(perturb_ret.success); + + // Export the TC into a Simplex_tree + Gudhi::Simplex_tree<> stree; + tc.create_complex(stree); +} diff --git a/src/cmake/modules/GUDHI_user_version_target.txt b/src/cmake/modules/GUDHI_user_version_target.txt index 0ab36cfc..51553e7e 100644 --- a/src/cmake/modules/GUDHI_user_version_target.txt +++ b/src/cmake/modules/GUDHI_user_version_target.txt @@ -48,7 +48,7 @@ if (NOT CMAKE_VERSION VERSION_LESS 2.8.11) add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/GudhUI ${GUDHI_USER_VERSION_DIR}/GudhUI) - set(GUDHI_MODULES "common;Alpha_complex;Bitmap_cubical_complex;Contraction;Hasse_complex;Persistent_cohomology;Simplex_tree;Skeleton_blocker;Spatial_searching;Subsampling;Witness_complex") + set(GUDHI_MODULES "common;Alpha_complex;Bitmap_cubical_complex;Contraction;Hasse_complex;Persistent_cohomology;Simplex_tree;Skeleton_blocker;Spatial_searching;Subsampling;Tangential_complex;Witness_complex") foreach(GUDHI_MODULE ${GUDHI_MODULES}) # doc files diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h index 21cf6925..fe23c4e7 100644 --- a/src/common/doc/main_page.h +++ b/src/common/doc/main_page.h @@ -93,6 +93,25 @@ </td> </tr> </table> + \subsection TangentialComplexDataStructure Tangential complex + \image html "tc_examples.png" "Tangential complex representation" +<table border="0"> + <tr> + <td width="25%"> + <b>Author:</b> Clément Jamin<br> + <b>Introduced in:</b> GUDHI 1.4.0<br> + <b>Copyright:</b> GPL v3<br> + </td> + <td width="75%"> + A Tangential Delaunay complex is a <a target="_blank" href="https://en.wikipedia.org/wiki/Simplicial_complex">simplicial complex</a> + designed to reconstruct a \f$ k \f$-dimensional manifold embedded in \f$ d \f$-dimensional Euclidean space. + The input is a point sample coming from an unknown manifold. + The running time depends only linearly on the extrinsic dimension \f$ d \f$ + and exponentially on the intrinsic dimension \f$ k \f$.<br> + <b>User manual:</b> \ref tangential_complex - <b>Reference manual:</b> Gudhi::tangential_complex::Tangential_complex + </td> + </tr> +</table> \subsection WitnessComplexDataStructure Witness complex \image html "Witness_complex_representation.png" "Witness complex representation" <table border="0"> @@ -337,6 +356,8 @@ make \endverbatim * @example Skeleton_blocker/Skeleton_blocker_from_simplices.cpp * @example Skeleton_blocker/Skeleton_blocker_iteration.cpp * @example Skeleton_blocker/Skeleton_blocker_link.cpp + * @example Tangential_complex/example_basic.cpp + * @example Tangential_complex/example_with_perturb.cpp * @example Witness_complex/witness_complex_from_file.cpp * @example Witness_complex/witness_complex_sphere.cpp */ diff --git a/src/common/include/gudhi/Clock.h b/src/common/include/gudhi/Clock.h index 04c6ffb9..77f196ca 100644 --- a/src/common/include/gudhi/Clock.h +++ b/src/common/include/gudhi/Clock.h @@ -27,47 +27,55 @@ #include <string> +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/src/common/include/gudhi/Debug_utils.h b/src/common/include/gudhi/Debug_utils.h index 7573a9db..8ed3b7b3 100644 --- a/src/common/include/gudhi/Debug_utils.h +++ b/src/common/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/src/common/include/gudhi/console_color.h b/src/common/include/gudhi/console_color.h new file mode 100644 index 00000000..c4671da3 --- /dev/null +++ b/src/common/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 <http://www.gnu.org/licenses/>. + */ + +#ifndef CONSOLE_COLOR_H_ +#define CONSOLE_COLOR_H_ + +#include <iostream> + +#if defined(WIN32) +#include <windows.h> +#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/src/common/include/gudhi/random_point_generators.h b/src/common/include/gudhi/random_point_generators.h new file mode 100644 index 00000000..3050b7ea --- /dev/null +++ b/src/common/include/gudhi/random_point_generators.h @@ -0,0 +1,477 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef RANDOM_POINT_GENERATORS_H_ +#define RANDOM_POINT_GENERATORS_H_ + +#include <CGAL/number_utils.h> +#include <CGAL/Random.h> +#include <CGAL/point_generators_d.h> + +#include <vector> // for vector<> + +namespace Gudhi { + +/////////////////////////////////////////////////////////////////////////////// +// Note: All these functions have been tested with the CGAL::Epick_d kernel +/////////////////////////////////////////////////////////////////////////////// + +// construct_point: dim 2 + +template <typename Kernel> +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> +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> +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> +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> +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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> points; + points.reserve(num_points); + for (std::size_t i = 0; i < num_points;) { + std::vector<FT> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> 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<FT> 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 <typename Kernel/*, typename TC_basis*/> +std::vector<typename Kernel::Point_d> 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<Point> 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 <typename Kernel, typename OutputIterator> +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<typename Kernel::FT> current_point = std::vector<typename Kernel::FT>()) { + CGAL::Random rng; + if (current_point.size() == 2 * dim) { + *out++ = k.construct_point_d_object()( + static_cast<int> (current_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<typename Kernel::FT> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> 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<typename Kernel::FT> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> generator(dim, radius); + std::vector<Point> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> generator(dim, radius); + std::vector<Point> points; + points.reserve(num_points); + + std::vector<FT> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> generator(3, sphere_radius); + std::vector<Point> points; + points.reserve(num_points); + + typename Kernel::Translated_point_d k_transl = + k.translated_point_d_object(); + 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<FT> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> 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<Point> 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 <typename Kernel> +std::vector<typename Kernel::Point_d> +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<Point> 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/src/common/include/gudhi_patches/CGAL/Convex_hull.h b/src/common/include/gudhi_patches/CGAL/Convex_hull.h new file mode 100644 index 00000000..a8f91bf8 --- /dev/null +++ b/src/common/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<typename CHTraits::Point_d>::type + Maximal_dimension_; + typedef typename Default::Get<TDS_, Triangulation_data_structure + < Maximal_dimension_, + Triangulation_vertex<CHTraits>, + Triangulation_full_cell<CHTraits> > + >::type TDS; + typedef Convex_hull<CHTraits, TDS_> 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/src/common/include/gudhi_patches/CGAL/Delaunay_triangulation.h b/src/common/include/gudhi_patches/CGAL/Delaunay_triangulation.h new file mode 100644 index 00000000..071cd184 --- /dev/null +++ b/src/common/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 <CGAL/tss.h> +#include <CGAL/Triangulation.h> +#include <CGAL/Dimension.h> +#include <CGAL/Default.h> + +#include <boost/iterator/transform_iterator.hpp> + +#include <algorithm> + +namespace CGAL { + +template< typename DCTraits, typename _TDS = Default > +class Delaunay_triangulation +: public Triangulation<DCTraits, + typename Default::Get<_TDS, Triangulation_data_structure< + typename DCTraits::Dimension, + Triangulation_vertex<DCTraits>, + Triangulation_full_cell<DCTraits> > + >::type > +{ + typedef typename DCTraits::Dimension Maximal_dimension_; + typedef typename Default::Get<_TDS, Triangulation_data_structure< + Maximal_dimension_, + Triangulation_vertex<DCTraits>, + Triangulation_full_cell<DCTraits> > + >::type TDS; + typedef Triangulation<DCTraits, TDS> Base; + typedef Delaunay_triangulation<DCTraits, _TDS> 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<Flat_orientation_d>* fop; + Construct_flat_orientation_d cfo; + In_flat_side_of_oriented_sphere_d ifsoos; + + Side_of_oriented_subsphere_d( + boost::optional<Flat_orientation_d>& x, + Construct_flat_orientation_d const&y, + In_flat_side_of_oriented_sphere_d const&z) + : fop(&x), cfo(y), ifsoos(z) {} + + template<class Iter> + 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<int, const Flat_orientation_d *> &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<Point> points(start, end); + spatial_sort(points.begin(), points.end(), geom_traits()); + Full_cell_handle hint; + for( typename std::vector<Point>::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<OrientationPredicate>(p_, s, ori_); + } + else + { + typedef typename Full_cell::Vertex_handle_const_iterator VHCI; + typedef Substitute_point_in_vertex_iterator<VHCI> 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<Coaffine_orientation_d, Side_of_oriented_subsphere_d> + Conflict_pred_in_subspace; + typedef Conflict_predicate<Orientation_d, Side_of_oriented_sphere_d> + Conflict_pred_in_fullspace; + typedef Conflict_traversal_predicate<Conflict_pred_in_subspace> + Conflict_traversal_pred_in_subspace; + typedef Conflict_traversal_predicate<Conflict_pred_in_fullspace> + Conflict_traversal_pred_in_fullspace; +}; + +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +// FUNCTIONS THAT ARE MEMBER METHODS: + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REMOVALS + +template< typename DCTraits, typename TDS > +typename Delaunay_triangulation<DCTraits, TDS>::Full_cell_handle +Delaunay_triangulation<DCTraits, TDS> +::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<Full_cell_handle> Simplices; + Simplices simps; + std::back_insert_iterator<Simplices> out(simps); + tds().incident_full_cells(v, out); + typedef std::set<Vertex_handle> 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<Geom_traits, Vertex_handle> Dark_vertex_base; + typedef Triangulation_full_cell<Geom_traits, + internal::Triangulation::Dark_full_cell_data<Self> > Dark_full_cell_base; + typedef Triangulation_data_structure<Maximal_dimension, Dark_vertex_base, Dark_full_cell_base> Dark_tds; + typedef Delaunay_triangulation<DCTraits, Dark_tds> 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<int, const Flat_orientation_d *>(current_dimension(), flat_orientation_.get_ptr()) + : std::pair<int, const Flat_orientation_d *>((std::numeric_limits<int>::max)(), (Flat_orientation_d*) NULL) ); + + Dark_s_handle dark_s; + Dark_v_handle dark_v; + typedef std::map<Vertex_handle, Dark_v_handle> 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_s_handle> Dark_full_cells; + Dark_full_cells conflict_zone; + std::back_insert_iterator<Dark_full_cells> 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<std::pair<Facet, Dark_facet> > 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<Facet, Dark_facet> 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<DCTraits, TDS> +::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<DCTraits, TDS>::Vertex_handle +Delaunay_triangulation<DCTraits, TDS> +::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<DCTraits, TDS>::Vertex_handle +Delaunay_triangulation<DCTraits, TDS> +::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<DCTraits, TDS>::Vertex_handle +Delaunay_triangulation<DCTraits, TDS> +::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_handle> Full_cell_h_vector; + CGAL_STATIC_THREAD_LOCAL_VARIABLE(Full_cell_h_vector,cs,0); + cs.clear(); + + std::back_insert_iterator<Full_cell_h_vector> 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<DCTraits, TDS> +::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<const Point *> 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<Self>(*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<typename Points::iterator, + internal::Triangulation::Point_from_pointer<Self>, + 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<DCTraits, TDS> +::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<DCTraits, TDS>::Facet +Delaunay_triangulation<DCTraits, TDS> +::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<DCTraits, TDS> +::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/src/common/include/gudhi_patches/CGAL/Epeck_d.h b/src/common/include/gudhi_patches/CGAL/Epeck_d.h new file mode 100644 index 00000000..52bce84c --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/Cartesian_base.h> +#include <CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h> +#include <CGAL/NewKernel_d/Kernel_d_interface.h> +#include <CGAL/internal/Exact_type_selector.h> + + +namespace CGAL { +#define CGAL_BASE \ + Cartesian_base_d<internal::Exact_field_selector<double>::Type, Dim> +template<class Dim> +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<Dim>, \ + Epeck_d<Dim> > > +template<class Dim> +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/src/common/include/gudhi_patches/CGAL/Epick_d.h b/src/common/include/gudhi_patches/CGAL/Epick_d.h new file mode 100644 index 00000000..64438539 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/Cartesian_base.h> +#include <CGAL/NewKernel_d/Cartesian_static_filters.h> +#include <CGAL/NewKernel_d/Cartesian_filter_K.h> +#include <CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h> +#include <CGAL/NewKernel_d/Kernel_d_interface.h> +#include <CGAL/internal/Exact_type_selector.h> +#include <CGAL/Interval_nt.h> +#include <CGAL/NewKernel_d/Types/Weighted_point.h> + + +namespace CGAL { +#define CGAL_BASE \ + Cartesian_filter_K< \ + Cartesian_base_d<double, Dim>, \ + Cartesian_base_d<Interval_nt_advanced, Dim>, \ + Cartesian_base_d<internal::Exact_field_selector<double>::Type, Dim> \ + > +template<class Dim> +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<Dim,Epick_d_help1<Dim>,Epick_d_help2<Dim> > +template<class Dim> +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<Dim>, \ + Epick_d<Dim> > > +template<class Dim> +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/src/common/include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h b/src/common/include/gudhi_patches/CGAL/IO/Triangulation_off_ostream.h new file mode 100644 index 00000000..701f0820 --- /dev/null +++ b/src/common/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 <CGAL/Epick_d.h> +#include <CGAL/Triangulation.h> +#include <sstream> +#include <iostream> + +namespace CGAL { + +namespace Triangulation_IO +{ +// TODO: test if the stream is binary or text? +template<typename Traits, typename P> +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<typename Traits, typename P> +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<typename Traits, typename FCH> +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<typename Traits, typename P> +void +input_point(std::istream & is, const Traits &traits, P & p) +{ + typedef typename Traits::FT FT; + std::vector<FT> 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<typename K> +std::istream & +operator>>(std::istream &is, typename Wrap::Point_d<K> & p) +{ + typedef typename Wrap::Point_d<K> P; + typedef typename K::FT FT; + std::vector<FT> 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<typename K> +std::istream & +operator>>(std::istream &is, typename Wrap::Weighted_point_d<K> & wp) +{ + typedef typename Wrap::Point_d<K> P; + typedef typename Wrap::Weighted_point_d<K> 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<FT> coords; + while (line_sstr >> temp) + coords.push_back(temp); + + typename std::vector<FT>::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<typename K> +std::istream & +operator>>(std::istream &is, typename Wrap::Vector_d<K> & v) +{ + typedef typename Wrap::Vector_d<K> V; + typedef typename K::FT FT; + std::vector<FT> 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<GT,TDS> & tr, + bool in_3D_export_surface_only = false) +{ + typedef Triangulation<GT,TDS> 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<Vertex_handle, int> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_base.h new file mode 100644 index 00000000..c13a9801 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/Origin.h> +#include <boost/type_traits/integral_constant.hpp> +#include <CGAL/representation_tags.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Uncertain.h> +#include <CGAL/typeset.h> +#include <CGAL/NewKernel_d/Dimension_base.h> +#include <CGAL/NewKernel_d/Cartesian_LA_functors.h> +#include <CGAL/NewKernel_d/Vector/array.h> +#include <CGAL/NewKernel_d/Vector/vector.h> +#include <CGAL/NewKernel_d/Vector/mix.h> +#ifdef CGAL_EIGEN3_ENABLED +#include <CGAL/NewKernel_d/LA_eigen/LA.h> +#else +#error Eigen3 is required +#endif + +namespace CGAL { + +template < typename FT_, typename Dim_, +#if 1 + typename Vec_=Mix_vector<Array_vector<FT_, Dim_>, + Vector_vector<FT_, Dim_>, + FT_, Dim_>, +#elif 0 + typename Vec_=Array_vector<FT_, Dim_>, +#elif 0 + typename Vec_=Vector_vector<FT_, Dim_>, +#else + // Dangerous because of alignment. Ok on x86_64 without AVX. + typename Vec_=LA_eigen<FT_, Dim_>, +#endif + typename LA_=LA_eigen<FT_,Dim_> > + /* Default LA to Vec or to LA_eigen? */ +struct Cartesian_LA_base_d : public Dimension_base<Dim_> +{ + typedef Cartesian_LA_base_d<FT_,Dim_> 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 <class> 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<class, class=void> struct Type {}; + template<class D> struct Type< Point_tag, D> { typedef Vector_ type; }; + template<class D> struct Type<Vector_tag, D> { typedef Vector_ type; }; + template<class D> struct Type< FT_tag, D> { typedef FT_ type; }; + template<class D> struct Type< RT_tag, D> { typedef FT_ type; }; + + typedef typeset<Point_tag> + ::add<Vector_tag>::type + // FIXME: These have nothing to do here. + ::add<Segment_tag>::type + ::add<Hyperplane_tag>::type + ::add<Sphere_tag>::type + ::add<Weighted_point_tag>::type + Object_list; + + typedef typeset< Point_cartesian_const_iterator_tag>::type + ::add<Vector_cartesian_const_iterator_tag>::type + Iterator_list; + + template<class, class=void, class=boost::integral_constant<int,0> > struct Functor { + typedef Null_functor type; + }; + template<class D> struct Functor<Construct_ttag<Vector_tag>,D> { + typedef CartesianDVectorBase::Construct_LA_vector<Self,Null_vector> type; + }; + template<class D> struct Functor<Construct_ttag<Point_tag>,D> { + typedef CartesianDVectorBase::Construct_LA_vector<Self,Origin> type; + }; + template<class D> struct Functor<Construct_ttag<Point_cartesian_const_iterator_tag>,D> { + typedef CartesianDVectorBase::Construct_cartesian_const_iterator<Self> type; + }; + template<class D> struct Functor<Construct_ttag<Vector_cartesian_const_iterator_tag>,D> { + typedef CartesianDVectorBase::Construct_cartesian_const_iterator<Self> type; + }; + template<class D> struct Functor<Sum_of_vectors_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_vector_plus_minus_tag>::value> > { + typedef CartesianDVectorBase::Sum_of_vectors<Self> type; + }; + template<class D> struct Functor<Difference_of_vectors_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_vector_plus_minus_tag>::value> > { + typedef CartesianDVectorBase::Difference_of_vectors<Self> type; + }; + template<class D> struct Functor<Opposite_vector_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_vector_plus_minus_tag>::value> > { + typedef CartesianDVectorBase::Opposite_vector<Self> type; + }; + template<class D> struct Functor<Midpoint_tag,D, + boost::integral_constant<int, + !LA_vector::template Property<Has_vector_plus_minus_tag>::value + || !LA_vector::template Property<Has_vector_scalar_ops_tag>::value> > { + typedef CartesianDVectorBase::Midpoint<Self> type; + }; + template<class D> struct Functor<Compute_point_cartesian_coordinate_tag,D> { + typedef CartesianDVectorBase::Compute_cartesian_coordinate<Self> type; + }; + template<class D> struct Functor<Compute_vector_cartesian_coordinate_tag,D> { + typedef CartesianDVectorBase::Compute_cartesian_coordinate<Self> type; + }; + template<class D> struct Functor<Point_dimension_tag,D> { + typedef CartesianDVectorBase::PV_dimension<Self> type; + }; + template<class D> struct Functor<Vector_dimension_tag,D> { + typedef CartesianDVectorBase::PV_dimension<Self> type; + }; + template<class D> struct Functor<Orientation_of_vectors_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_determinant_of_iterator_to_vectors_tag>::value> > { + typedef CartesianDVectorBase::Orientation_of_vectors<Self> type; + }; + template<class D> struct Functor<Orientation_of_points_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_determinant_of_iterator_to_points_tag>::value> > { + typedef CartesianDVectorBase::Orientation_of_points<Self> type; + }; + template<class D> struct Functor<Scalar_product_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Has_dot_product_tag>::value> > { + typedef CartesianDVectorBase::Scalar_product<Self> type; + }; + template<class D> struct Functor<Squared_distance_to_origin_tag,D, + boost::integral_constant<int,!LA_vector::template Property<Stores_squared_norm_tag>::value> > { + typedef CartesianDVectorBase::Squared_distance_to_origin_stored<Self> type; + }; + // Use integral_constant<int,2> in case of failure, to distinguish from the previous one. + template<class D> struct Functor<Squared_distance_to_origin_tag,D, + boost::integral_constant<int, + (LA_vector::template Property<Stores_squared_norm_tag>::value + || !LA_vector::template Property<Has_dot_product_tag>::value)*2> > { + typedef CartesianDVectorBase::Squared_distance_to_origin_via_dotprod<Self> type; + }; + template<class D> struct Functor<Point_to_vector_tag,D> { + typedef CartesianDVectorBase::Identity_functor<Self> type; + }; + template<class D> struct Functor<Vector_to_point_tag,D> { + typedef CartesianDVectorBase::Identity_functor<Self> type; + }; + + CGAL_CONSTEXPR Cartesian_LA_base_d(){} + CGAL_CONSTEXPR Cartesian_LA_base_d(int d):Dimension_base<Dim_>(d){} +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_LA_BASE_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_LA_functors.h new file mode 100644 index 00000000..871c463a --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/utils.h> +#include <CGAL/is_iterator.h> +#include <CGAL/argument_swaps.h> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <CGAL/Dimension.h> + +namespace CGAL { +namespace CartesianDVectorBase { +#ifndef CGAL_CXX11 +namespace internal { +template<class R_,class Dim_> struct Construct_LA_vector_ { + struct Never_use {}; + void operator()(Never_use)const; +}; +#define CGAL_CODE(Z,N,_) template<class R> struct Construct_LA_vector_<R,Dimension_tag<N> > { \ + typedef typename R::Constructor Constructor; \ + typedef typename Get_type<R, RT_tag>::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<class R_,class Zero_> struct Construct_LA_vector +: private Store_kernel<R_> +#ifndef CGAL_CXX11 +, public internal::Construct_LA_vector_<R_,typename R_::Default_ambient_dimension> +#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<R, RT_tag>::type RT; + typedef typename Get_type<R, FT_tag>::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<class...U> + typename std::enable_if<Constructible_from_each<RT,U...>::value && + boost::is_same<Dimension_tag<sizeof...(U)>, Dimension>::value, + result_type>::type + operator()(U&&...u)const{ + return typename Constructor::Values()(std::forward<U>(u)...); + } + //template<class...U,class=typename std::enable_if<Constructible_from_each<RT,U...>::value>::type,class=typename std::enable_if<(sizeof...(U)==static_dim+1)>::type,class=void> + template<class...U> + typename std::enable_if<Constructible_from_each<RT,U...>::value && + boost::is_same<Dimension_tag<sizeof...(U)-1>, Dimension>::value, + result_type>::type + operator()(U&&...u)const{ + return Apply_to_last_then_rest()(typename Constructor::Values_divide(),std::forward<U>(u)...); + } +#else + using internal::Construct_LA_vector_<R_,typename R::Default_ambient_dimension>::operator(); +#endif + template<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,result_type>::type operator() + (Iter f,Iter g,Cartesian_tag t)const + { + return this->operator()((int)std::distance(f,g),f,g,t); + } + template<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,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<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::bidirectional_iterator_tag>,result_type>::type operator() + (Iter f,Iter g,Homogeneous_tag)const + { + --g; + return this->operator()((int)std::distance(f,g),f,g,*g); + } + template<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::bidirectional_iterator_tag>,result_type>::type operator() + (int d,Iter f,Iter g,Homogeneous_tag)const + { + --g; + return this->operator()(d,f,g,*g); + } + template<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,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<class Iter> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,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<class Iter,class NT> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,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<FT,NT>(l)),CGAL::make_transforming_iterator(g,Divide<FT,NT>(l))); + } + template<class Iter,class NT> inline + typename boost::enable_if<is_iterator_type<Iter,std::forward_iterator_tag>,result_type>::type operator() + (Iter f,Iter g,NT const&l)const + { + return this->operator()((int)std::distance(f,g),f,g,l); + } +}; + +template<class R_> struct Compute_cartesian_coordinate { + CGAL_FUNCTOR_INIT_IGNORE(Compute_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::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<const first_argument_type>()[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<class R_> 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<class R_> struct Midpoint { + CGAL_FUNCTOR_INIT_IGNORE(Midpoint) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type first_argument_type; + typedef typename Get_type<R, Point_tag>::type second_argument_type; + typedef typename Get_type<R, Point_tag>::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return (a+b)/2; + } +}; + +template<class R_> struct Sum_of_vectors { + CGAL_FUNCTOR_INIT_IGNORE(Sum_of_vectors) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type first_argument_type; + typedef typename Get_type<R, Vector_tag>::type second_argument_type; + typedef typename Get_type<R, Vector_tag>::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return a+b; + } +}; + +template<class R_> struct Difference_of_vectors { + CGAL_FUNCTOR_INIT_IGNORE(Difference_of_vectors) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type first_argument_type; + typedef typename Get_type<R, Vector_tag>::type second_argument_type; + typedef typename Get_type<R, Vector_tag>::type result_type; + + result_type operator()(result_type const& a, result_type const& b)const{ + return a-b; + } +}; + +template<class R_> struct Opposite_vector { + CGAL_FUNCTOR_INIT_IGNORE(Opposite_vector) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type result_type; + typedef typename Get_type<R, Vector_tag>::type argument_type; + + result_type operator()(result_type const& v)const{ + return -v; + } +}; + +template<class R_> struct Scalar_product { + CGAL_FUNCTOR_INIT_IGNORE(Scalar_product) + typedef R_ R; + typedef typename R::LA_vector LA; + typedef typename Get_type<R, RT_tag>::type result_type; + typedef typename Get_type<R, Vector_tag>::type first_argument_type; + typedef typename Get_type<R, Vector_tag>::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<class R_> 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<R, RT_tag>::type result_type; + typedef typename Get_type<R, Point_tag>::type argument_type; + + result_type operator()(argument_type const& a)const{ + return LA::squared_norm(a); + } +}; + +template<class R_> 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<R, RT_tag>::type result_type; + typedef typename Get_type<R, Point_tag>::type argument_type; + + result_type operator()(argument_type const& a)const{ + return LA::dot_product(a,a); + } +}; + +template<class R_> 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<R, Orientation_tag>::type result_type; + typedef typename R::LA_vector LA; + + template<class Iter> + result_type operator()(Iter const& f, Iter const& e) const { + return LA::determinant_of_iterators_to_vectors(f,e); + } +}; + +template<class R_> 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<R, Orientation_tag>::type result_type; + typedef typename R::LA_vector LA; + + template<class Iter> + result_type operator()(Iter const& f, Iter const& e) const { + return LA::determinant_of_iterators_to_points(f,e); + } +}; + +template<class R_> 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<class T> + result_type operator()(T const& v) const { + return LA::size_of_vector(v); + } +}; + +template<class R_> struct Identity_functor { + CGAL_FUNCTOR_INIT_IGNORE(Identity_functor) + template<class T> + T const& operator()(T const&t) const { return t; } +}; + +} +} // namespace CGAL +#endif // CGAL_CARTESIAN_LA_FUNCTORS_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_base.h new file mode 100644 index 00000000..641bf8ae --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/NewKernel_d/Cartesian_complete.h> +#include <CGAL/NewKernel_d/Cartesian_LA_base.h> + +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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_change_FT.h new file mode 100644 index 00000000..e09c72d0 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/NT_converter.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/Cartesian_complete.h> + +namespace CGAL { + +template < typename Base_, typename FT_, typename LA_=CGAL::LA_eigen<FT_,typename Base_::Default_ambient_dimension> > +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 <class T, class D=void> struct Type : Inherit_type<Base_, T> {}; + template <class D> struct Type <FT_tag, D> { typedef FT_ type; }; + template <class D> struct Type <RT_tag, D> { typedef FT_ type; }; + + typedef NT_converter<typename Get_type<Kernel_base, FT_tag>::type,FT_> FT_converter; + typedef transforming_iterator<FT_converter,typename Kernel_base::Point_cartesian_const_iterator> Point_cartesian_const_iterator; + typedef transforming_iterator<FT_converter,typename Kernel_base::Vector_cartesian_const_iterator> Vector_cartesian_const_iterator; + //FIXME: use Iterator_list! + /* + template<class T,bool=CGAL_BOOSTD is_same<typename iterator_tag_traits<T>::value_tag,FT_tag>::value> + struct Iterator : Get_type<Kernel_base,T> {}; + template<class T> struct Iterator<T,true> { + typedef transforming_iterator<FT_converter,typename Get_type<Kernel_base,T>::type> type; + }; + */ + + template<class Tag_,class Type_> + struct Construct_cartesian_const_iterator_ { + typedef typename Get_functor<Kernel_base, Tag_>::type Functor_base; + Construct_cartesian_const_iterator_(){} + Construct_cartesian_const_iterator_(Self const&r):f(r){} + Functor_base f; + typedef Type_ result_type; + template<class T> + result_type operator()(T const& v, Begin_tag)const{ + return make_transforming_iterator(f(v,Begin_tag()),FT_converter()); + } + template<class T> + result_type operator()(T const& v, End_tag)const{ + return make_transforming_iterator(f(v,End_tag()),FT_converter()); + } + }; + typedef Construct_cartesian_const_iterator_<Construct_ttag<Point_cartesian_const_iterator_tag>,Point_cartesian_const_iterator> Construct_point_cartesian_const_iterator; + typedef Construct_cartesian_const_iterator_<Construct_ttag<Vector_cartesian_const_iterator_tag>,Vector_cartesian_const_iterator> Construct_vector_cartesian_const_iterator; + + template<class Tag_> + struct Compute_cartesian_coordinate { + typedef typename Get_functor<Kernel_base, Tag_>::type Functor_base; + Compute_cartesian_coordinate(){} + Compute_cartesian_coordinate(Self const&r):f(r){} + Functor_base f; + typedef FT_ result_type; + template<class Obj_> + result_type operator()(Obj_ const& v,int i)const{ + return FT_converter()(f(v,i)); + } + }; + + template<class T,class U=void,class=typename Get_functor_category<Cartesian_change_FT_base,T>::type> struct Functor : + Inherit_functor<Kernel_base,T,U> { }; + template<class T,class U> struct Functor<T,U,Compute_tag> { }; + template<class T,class U> struct Functor<T,U,Predicate_tag> { }; + template<class D> struct Functor<Compute_point_cartesian_coordinate_tag,D,Compute_tag> { + typedef Compute_cartesian_coordinate<Compute_point_cartesian_coordinate_tag> type; + }; + template<class D> struct Functor<Compute_vector_cartesian_coordinate_tag,D,Compute_tag> { + typedef Compute_cartesian_coordinate<Compute_vector_cartesian_coordinate_tag> type; + }; + template<class D> struct Functor<Construct_ttag<Point_cartesian_const_iterator_tag>,D,Construct_iterator_tag> { + typedef Construct_point_cartesian_const_iterator type; + }; + template<class D> struct Functor<Construct_ttag<Vector_cartesian_const_iterator_tag>,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<Base_,FT_> +{ + CGAL_CONSTEXPR Cartesian_change_FT(){} + CGAL_CONSTEXPR Cartesian_change_FT(int d):Cartesian_change_FT_base<Base_,FT_>(d){} +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_CHANGE_FT_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_complete.h new file mode 100644 index 00000000..ef8921db --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/function_objects_cartesian.h> +#include <CGAL/NewKernel_d/Cartesian_per_dimension.h> +#include <CGAL/NewKernel_d/Types/Segment.h> +#include <CGAL/NewKernel_d/Types/Sphere.h> +#include <CGAL/NewKernel_d/Types/Hyperplane.h> +#include <CGAL/NewKernel_d/Types/Aff_transformation.h> +#include <CGAL/NewKernel_d/Types/Line.h> +#include <CGAL/NewKernel_d/Types/Ray.h> +#include <CGAL/NewKernel_d/Types/Iso_box.h> + +#endif // CGAL_KERNEL_D_CARTESIAN_COMPLETE_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_K.h new file mode 100644 index 00000000..179e97bf --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/NewKernel_d/KernelD_converter.h> +#include <CGAL/NewKernel_d/Filtered_predicate2.h> +#include <boost/mpl/if.hpp> +#include <boost/mpl/and.hpp> + +namespace CGAL { + +template < typename Base_, typename AK_, typename EK_ > +struct Cartesian_filter_K : public Base_, + private Store_kernel<AK_>, private Store_kernel2<EK_> +{ + 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<AK_>(a),Store_kernel2<EK_>(b){} + CGAL_CONSTEXPR Cartesian_filter_K(int d,AK_ const&a,EK_ const&b):Base_(d),Store_kernel<AK_>(a),Store_kernel2<EK_>(b){} + typedef Base_ Kernel_base; + typedef AK_ AK; + typedef EK_ EK; + typedef typename Store_kernel<AK_>::reference_type AK_rt; + AK_rt approximate_kernel()const{return this->kernel();} + typedef typename Store_kernel2<EK_>::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<Kernel_base>, + internal::Do_not_store_kernel<AK>, + internal::Do_not_store_kernel<EK> > Do_not_store_kernel; + + //TODO: C2A/C2E could be able to convert *this into this->kernel() or this->kernel2(). + typedef KernelD_converter<Kernel_base,AK> C2A; + typedef KernelD_converter<Kernel_base,EK> C2E; + + // fix the types + // TODO: only fix some types, based on some criterion? + template<class T> struct Type : Get_type<Kernel_base,T> {}; + + template<class T,class D=void,class=typename Get_functor_category<Cartesian_filter_K,T>::type> struct Functor : + Inherit_functor<Kernel_base,T,D> {}; + template<class T,class D> struct Functor<T,D,Predicate_tag> { + typedef typename Get_functor<AK, T>::type AP; + typedef typename Get_functor<EK, T>::type EP; + typedef Filtered_predicate2<EP,AP,C2E,C2A> type; + }; +// TODO: +// template<class T> struct Functor<T,No_filter_tag,Predicate_tag> : +// Kernel_base::template Functor<T,No_filter_tag> {}; +// TODO: +// detect when Less_cartesian_coordinate doesn't need filtering +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_FILTER_K_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_filter_NT.h new file mode 100644 index 00000000..c390a55c --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/NewKernel_d/Cartesian_change_FT.h> +#include <CGAL/internal/Exact_type_selector.h> + +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<Kernel_base,Interval_nt_advanced> K1; + typedef typename internal::Exact_field_selector<typename Get_type<Kernel_base, FT_tag>::type>::Type Exact_nt; + typedef Cartesian_change_FT<Kernel_base,Exact_nt> K2; + + template<class T,class D=void,class=typename Get_functor_category<Cartesian_filter_NT,T>::type> struct Functor : + Inherit_functor<Kernel_base,T,D> {}; + template<class T,class D> struct Functor<T,D,Predicate_tag> { + struct type { + //TODO: use compression (derive from a compressed_pair?) + typedef typename Get_functor<K1, T>::type P1; P1 p1; + typedef typename Get_functor<K2, T>::type P2; P2 p2; + typedef typename P2::result_type result_type; + type(){} + type(Cartesian_filter_NT const&k):p1(reinterpret_cast<K1 const&>(k)),p2(reinterpret_cast<K2 const&>(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<class...U> result_type operator()(U&&...u)const{ + { + Protect_FPU_rounding<true> 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>(u)...); + } +#else + result_type operator()()const{ // does it make sense to have 0 argument? + { + Protect_FPU_rounding<true> 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<BOOST_PP_ENUM_PARAMS(N,class T)> result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t))const{ \ + { \ + Protect_FPU_rounding<true> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_per_dimension.h new file mode 100644 index 00000000..179f7319 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> +#include <CGAL/predicates/sign_of_determinant.h> + +// Should probably disappear. + +namespace CGAL { +template <class Dim_, class R_, class Derived_> +struct Cartesian_per_dimension : public R_ {}; +} + +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Cartesian_static_filters.h new file mode 100644 index 00000000..693e962a --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> +#include <CGAL/internal/Static_filters/tools.h> // bug, should be included by the next one +#include <CGAL/internal/Static_filters/Orientation_2.h> +#include <boost/mpl/if.hpp> + +namespace CGAL { +namespace SFA { // static filter adapter +// Note that this would be quite a bit simpler without stateful kernels +template <class Base_,class R_> struct Orientation_of_points_2 : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points_2) + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Orientation_tag>::type result_type; + typedef typename Get_type<R_, FT_tag>::type FT; + typedef typename Get_functor<R_, Compute_point_cartesian_coordinate_tag>::type CC; + typedef typename Get_functor<Base_, Orientation_of_points_tag>::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<Dereference_functor>(t+0),make_transforming_iterator<Dereference_functor>(t+3)); + } + }; + }; + template<class Iter> 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<Adapter>()(P(this->kernel(),c,A),P(this->kernel(),c,B),P(this->kernel(),c,C)); + } +}; +} + +template <class Dim_ /* should be implicit */, class R_, class Derived_=Default> +struct Cartesian_static_filters : public R_ { + CGAL_CONSTEXPR Cartesian_static_filters(){} + CGAL_CONSTEXPR Cartesian_static_filters(int d):R_(d){} +}; + +template <class R_, class Derived_> +struct Cartesian_static_filters<Dimension_tag<2>, R_, Derived_> : public R_ { + CGAL_CONSTEXPR Cartesian_static_filters(){} + CGAL_CONSTEXPR Cartesian_static_filters(int d):R_(d){} + typedef Cartesian_static_filters<Dimension_tag<2>, R_, Derived_> Self; + typedef typename Default::Get<Derived_,Self>::type Derived; + template <class T, class=void> struct Functor : Inherit_functor<R_, T> {}; + template <class D> struct Functor <Orientation_of_points_tag,D> { + typedef + //typename boost::mpl::if_ < + //boost::is_same<D,No_filter_tag>, + //typename Get_functor<R_, Orientation_of_points_tag>::type, + SFA::Orientation_of_points_2<R_,Derived> + // >::type + type; + }; +}; + +} + +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Coaffine.h new file mode 100644 index 00000000..43015d24 --- /dev/null +++ b/src/common/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 <vector> +#include <algorithm> +#include <iterator> +#include <CGAL/Dimension.h> +#include <CGAL/NewKernel_d/functor_tags.h> + +namespace CGAL { +namespace CartesianDKernelFunctors { +struct Flat_orientation { + std::vector<int> proj; + std::vector<int> rest; + bool reverse; +}; + +// For debugging purposes +inline std::ostream& operator<< (std::ostream& o, Flat_orientation const& f) { + o << "Proj: "; + for(std::vector<int>::const_iterator i=f.proj.begin(); + i!=f.proj.end(); ++i) + o << *i << ' '; + o << "\nRest: "; + for(std::vector<int>::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<class Mat> +inline void debug_matrix(std::ostream& o, Mat const&mat) { + for(int i=0;i<mat.rows();++i){ + for(int j=0;j<mat.cols();++j){ + o<<mat(i,j)<<' '; + } + o<<'\n'; + } +} +} +} + +template<class R_> struct Construct_flat_orientation : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_flat_orientation) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type Dplusone; + typedef typename R::LA::template Rebind_dimension<Dynamic_dimension_tag,Dplusone>::Other LA; + typedef typename LA::Square_matrix Matrix; + typedef typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type CCC; + typedef typename Get_functor<R, Point_dimension_tag>::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<class Iter> + 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<int>& proj=o.proj; + std::vector<int>& rest=o.rest; rest.reserve(dim+1); + for(int i=0; i<dim+1; ++i) rest.push_back(i); + for( ; f != e ; ++col, ++f ) { + //std::cerr << "(*f)[0]=" << (*f)[0] << std::endl; + Point const&p=*f; + // use a coordinate iterator instead? + for(int i=0; i<dim; ++i) coord(col, i) = ccc(p, i); + coord(col,dim)=1; + int d = (int)proj.size()+1; + Matrix m (d, d); + // Fill the matrix with what we already have + for(int i=0; i<d; ++i) + for(int j=0; j<d-1; ++j) + m(i,j) = coord(i, proj[j]); + // Try to complete with any other coordinate + // TODO: iterate on rest by the end, or use a (forward_)list. + for(std::vector<int>::iterator it=rest.begin();;++it) { + CGAL_assertion(it!=rest.end()); + for(int i=0; i<d; ++i) m(i,d-1) = coord(i, *it); + if(LA::sign_of_determinant(m)!=0) { + proj.push_back(*it); + rest.erase(it); + break; + } + } + } + std::sort(proj.begin(),proj.end()); + typename Get_functor<R, In_flat_orientation_tag>::type ifo(this->kernel()); + o.reverse = false; + o.reverse = ifo(o, f_save, e) != CGAL::POSITIVE; + return o; + } +}; + +template<class R_> struct Contained_in_affine_hull : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Contained_in_affine_hull) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type CCC; + typedef typename Get_functor<R, Point_dimension_tag>::type PD; + //typedef typename Increment_dimension<typename R::Default_ambient_dimension>::type D1; + //typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type D2; + //typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type Dplusone; + typedef typename R::LA::template Rebind_dimension<Dynamic_dimension_tag,Dplusone>::Other LA; + typedef typename LA::Square_matrix Matrix; + + // mostly copied from Construct_flat_orientation. TODO: dedup this code or use LA. + template<class Iter> + result_type operator()(Iter f, Iter e, Point const&x) const { + // FIXME: are the points in (f,e) required to be affinely independent? + PD pd (this->kernel()); + CCC ccc (this->kernel()); + int dim=pd(*f); + Matrix coord (dim+1, dim+1); // use distance + int col = 0; + std::vector<int> proj; + std::vector<int> rest; rest.reserve(dim+1); + for(int i=0; i<dim+1; ++i) rest.push_back(i); + for( ; f != e ; ++col, ++f ) { + Point const&p=*f; + for(int i=0; i<dim; ++i) coord(col, i) = ccc(p, i); + coord(col,dim)=1; + int d = (int)proj.size()+1; + Matrix m (d, d); + for(int i=0; i<d; ++i) + for(int j=0; j<d-1; ++j) + m(i,j) = coord(i, proj[j]); + for(std::vector<int>::iterator it=rest.begin();it!=rest.end();++it) { + for(int i=0; i<d; ++i) m(i,d-1) = coord(i, *it); + if(LA::sign_of_determinant(m)!=0) { + proj.push_back(*it); + rest.erase(it); + break; + } + } + } + for(int i=0; i<dim; ++i) coord(col, i) = ccc(x, i); + coord(col,dim)=1; + int d = (int)proj.size()+1; + Matrix m (d, d); + for(int i=0; i<d; ++i) + for(int j=0; j<d-1; ++j) + m(i,j) = coord(i, proj[j]); + for(std::vector<int>::iterator it=rest.begin();it!=rest.end();++it) { + for(int i=0; i<d; ++i) m(i,d-1) = coord(i, *it); + if(LA::sign_of_determinant(m)!=0) return false; + } + return true; + } +}; + +template<class R_> struct In_flat_orientation : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(In_flat_orientation) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Square_matrix Matrix; + + template<class Iter> + result_type operator()(Flat_orientation const&o, Iter f, Iter e) const { + // TODO: work in the projection instead of the ambient space. + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + int d=pd(*f); + Matrix m(d+1,d+1); + int i=0; + for(;f!=e;++f,++i) { + Point const& p=*f; + m(i,0)=1; + for(int j=0;j<d;++j){ + m(i,j+1)=c(p,j); + } + } + for(std::vector<int>::const_iterator it = o.rest.begin(); it != o.rest.end() /* i<d+1 */; ++i, ++it) { + m(i,0)=1; + for(int j=0;j<d;++j){ + m(i,j+1)=0; // unneeded if the matrix is initialized to 0 + } + if(*it != d) m(i,1+*it)=1; + } + + result_type ret = LA::sign_of_determinant(CGAL_MOVE(m)); + if(o.reverse) ret=-ret; + return ret; + } +}; + +template<class R_> struct In_flat_side_of_oriented_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(In_flat_side_of_oriented_sphere) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension,2>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension,2>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Square_matrix Matrix; + + template<class Iter> + result_type operator()(Flat_orientation const&o, Iter f, Iter e, Point const&x) const { + // TODO: can't work in the projection, but we should at least remove the row of 1s. + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + int d=pd(*f); + Matrix m(d+2,d+2); + int i=0; + for(;f!=e;++f,++i) { + Point const& p=*f; + m(i,0)=1; + m(i,d+1)=0; + for(int j=0;j<d;++j){ + m(i,j+1)=c(p,j); + m(i,d+1)+=CGAL_NTS square(m(i,j+1)); + } + } + for(std::vector<int>::const_iterator it = o.rest.begin(); it != o.rest.end() /* i<d+1 */; ++i, ++it) { + m(i,0)=1; + for(int j=0;j<d;++j){ + m(i,j+1)=0; // unneeded if the matrix is initialized to 0 + } + if(*it != d) m(i,d+1)=m(i,1+*it)=1; + else m(i,d+1)=0; + } + m(d+1,0)=1; + m(d+1,d+1)=0; + for(int j=0;j<d;++j){ + m(d+1,j+1)=c(x,j); + m(d+1,d+1)+=CGAL_NTS square(m(d+1,j+1)); + } + + result_type ret = -LA::sign_of_determinant(CGAL_MOVE(m)); + if(o.reverse) ret=-ret; + return ret; + } +}; + +template<class R_> struct In_flat_power_side_of_power_sphere_raw : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(In_flat_power_side_of_power_sphere_raw) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension,2>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension,2>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Square_matrix Matrix; + + template<class Iter, class IterW, class Wt> + result_type operator()(Flat_orientation const&o, Iter f, Iter e, IterW fw, Point const&x, Wt const&w) const { + // TODO: can't work in the projection, but we should at least remove the row of 1s. + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + int d=pd(*f); + Matrix m(d+2,d+2); + int i=0; + for(;f!=e;++f,++fw,++i) { + Point const& p=*f; + m(i,0)=1; + m(i,d+1)=-*fw; + for(int j=0;j<d;++j){ + m(i,j+1)=c(p,j); + m(i,d+1)+=CGAL_NTS square(m(i,j+1)); + } + } + for(std::vector<int>::const_iterator it = o.rest.begin(); it != o.rest.end() /* i<d+1 */; ++i, ++it) { + m(i,0)=1; + for(int j=0;j<d;++j){ + m(i,j+1)=0; // unneeded if the matrix is initialized to 0 + } + if(*it != d) m(i,d+1)=m(i,1+*it)=1; + else m(i,d+1)=0; + } + m(d+1,0)=1; + m(d+1,d+1)=-w; + for(int j=0;j<d;++j){ + m(d+1,j+1)=c(x,j); + m(d+1,d+1)+=CGAL_NTS square(m(d+1,j+1)); + } + + result_type ret = -LA::sign_of_determinant(CGAL_MOVE(m)); + if(o.reverse) ret=-ret; + return ret; + } +}; + + +} +CGAL_KD_DEFAULT_TYPE(Flat_orientation_tag,(CGAL::CartesianDKernelFunctors::Flat_orientation),(),()); +CGAL_KD_DEFAULT_FUNCTOR(In_flat_orientation_tag,(CartesianDKernelFunctors::In_flat_orientation<K>),(Point_tag),(Compute_point_cartesian_coordinate_tag,Point_dimension_tag)); +CGAL_KD_DEFAULT_FUNCTOR(In_flat_side_of_oriented_sphere_tag,(CartesianDKernelFunctors::In_flat_side_of_oriented_sphere<K>),(Point_tag),(Compute_point_cartesian_coordinate_tag,Point_dimension_tag)); +CGAL_KD_DEFAULT_FUNCTOR(In_flat_power_side_of_power_sphere_raw_tag,(CartesianDKernelFunctors::In_flat_power_side_of_power_sphere_raw<K>),(Point_tag),(Compute_point_cartesian_coordinate_tag,Point_dimension_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Construct_flat_orientation_tag,(CartesianDKernelFunctors::Construct_flat_orientation<K>),(Point_tag),(Compute_point_cartesian_coordinate_tag,Point_dimension_tag,In_flat_orientation_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Contained_in_affine_hull_tag,(CartesianDKernelFunctors::Contained_in_affine_hull<K>),(Point_tag),(Compute_point_cartesian_coordinate_tag,Point_dimension_tag)); +} +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Define_kernel_types.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Define_kernel_types.h new file mode 100644 index 00000000..6a40515b --- /dev/null +++ b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Define_kernel_types.h @@ -0,0 +1,50 @@ +// 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_DEFINE_KERNEL_TYPES_H +#define CGAL_DEFINE_KERNEL_TYPES_H +#include <CGAL/config.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/typeset.h> +#ifdef CGAL_CXX11 +#include <type_traits> +#else +#include <boost/type_traits.hpp> +#endif + +namespace CGAL { + namespace internal { + template<class K,class Tag_,bool=iterator_tag_traits<Tag_>::is_iterator> + struct Type_or_iter : K::template Type<Tag_> {}; + template<class K,class Tag_> + struct Type_or_iter<K, Tag_, true> : K::template Iterator<Tag_> {}; + } + template<class K, class Base=K, class List=typename typeset_union<typename K::Object_list,typename K::Iterator_list>::type> struct Define_kernel_types; + template<class K, class Base> + struct Define_kernel_types <K, Base, typeset<> > : Base {}; + template<class K> + struct Define_kernel_types <K, void, typeset<> > {}; + template<class K, class Base, class List> + struct Define_kernel_types : + Typedef_tag_type<typename List::head, + typename internal::Type_or_iter<K,typename List::head>::type, + Define_kernel_types<K, Base, typename List::tail> + > {}; +} +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Dimension_base.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Dimension_base.h new file mode 100644 index 00000000..be875e63 --- /dev/null +++ b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Dimension_base.h @@ -0,0 +1,49 @@ +// 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_DIMENSION_BASE_h +#define CGAL_KD_DIMENSION_BASE_h +#include <CGAL/Dimension.h> +#include <CGAL/assertions.h> +#include <CGAL/NewKernel_d/utils.h> +namespace CGAL { +struct Store_dimension_base { + //TODO: add some assertions + Store_dimension_base(int dim=UNKNOWN_DIMENSION):dim_(dim){} + int dimension()const{return dim_;} + void set_dimension(int dim){dim_=dim;} + private: + int dim_; +}; +template<class=Dynamic_dimension_tag> +struct Dimension_base { + Dimension_base(int = UNKNOWN_DIMENSION){} + int dimension() const { return UNKNOWN_DIMENSION; } + void set_dimension(int) {} +}; +template<int dim_> +struct Dimension_base<Dimension_tag<dim_> > { + Dimension_base(){} + Dimension_base(int CGAL_assertion_code(dim)){CGAL_assertion(dim_==dim);} + int dimension()const{return dim_;} + void set_dimension(int dim){CGAL_assertion(dim_==dim);} +}; +} +#endif + diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Filtered_predicate2.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Filtered_predicate2.h new file mode 100644 index 00000000..1a6a67bc --- /dev/null +++ b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Filtered_predicate2.h @@ -0,0 +1,137 @@ +// Copyright (c) 2001-2005 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) : Sylvain Pion + +#ifndef CGAL_FILTERED_PREDICATE2_H +#define CGAL_FILTERED_PREDICATE2_H + +#include <string> +#include <CGAL/config.h> +#include <CGAL/Interval_nt.h> +#include <CGAL/Uncertain.h> +#include <CGAL/Profile_counter.h> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <boost/preprocessor.hpp> + +namespace CGAL { + +// This template class is a wrapper that implements the filtering for any +// predicate (dynamic filters with IA). + +// TODO : +// - each predicate in the default kernel should define a tag that says if it +// wants to be filtered or not (=> all homogeneous predicate define this +// tag). We could even test-suite that automatically. It makes a strong +// new requirement on the kernel though... +// Could be done with a traits mechanism ? +// A default template could use the current IA, but other tags or whatever +// could specify no filtering at all, or static filtering... +// - same thing for constructions => virtual operator() ? +// - similarly, constructions should have a tag saying if they can throw or +// not, or we let all this up to the compiler optimizer to figure out ? +// - Some caching could be done at the Point_2 level. + + +template <class EP, class AP, class C2E, class C2A, bool Protection = true> +class Filtered_predicate2 +{ +//TODO: pack (at least use a tuple) +//FIXME: is it better to store those, or just store enough to recreate them +//(i.e. possibly references to the kernels)? + EP ep; + AP ap; + C2E c2e; + C2A c2a; + + typedef typename AP::result_type Ares; + +public: + + typedef AP Approximate_predicate; + typedef EP Exact_predicate; + typedef C2E To_exact_converter; + typedef C2A To_approximate_converter; + + // FIXME: should use result_of, see emails by Nico + typedef typename EP::result_type result_type; + // AP::result_type must be convertible to EP::result_type. + + Filtered_predicate2() + {} + + template <class K> + Filtered_predicate2(const K& k) + : ep(k.exact_kernel()), ap(k.approximate_kernel()), c2e(k,k.exact_kernel()), c2a(k,k.approximate_kernel()) + {} + +#ifdef CGAL_CXX11 + template <typename... Args> + result_type + operator()(Args&&... args) const + { + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + // Protection is outside the try block as VC8 has the CGAL_CFG_FPU_ROUNDING_MODE_UNWINDING_VC_BUG + { + Protect_FPU_rounding<Protection> 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<!Protection> p(CGAL_FE_TONEAREST); + return ep(c2e(std::forward<Args>(args))...); + } +#else + +#define CGAL_VAR(Z,N,C) C(a##N) +#define CGAL_CODE(Z,N,_) \ + template <BOOST_PP_ENUM_PARAMS(N,class A)> \ + 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<Protection> 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<!Protection> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/KernelD_converter.h new file mode 100644 index 00000000..a8896976 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/tuple.h> +#include <CGAL/typeset.h> +#include <CGAL/Object.h> +#include <CGAL/Origin.h> +#include <CGAL/NT_converter.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/is_iterator.h> +#include <CGAL/transforming_iterator.h> +#include <boost/utility/enable_if.hpp> +#include <boost/mpl/if.hpp> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <CGAL/NewKernel_d/Kernel_object_converter.h> + +namespace CGAL { +namespace internal { +// Reverses order, but that shouldn't matter. +template<class K,class T> struct Map_taglist_to_typelist : + Map_taglist_to_typelist<K,typename T::tail>::type + ::template add<typename Get_type<K, typename T::head>::type> +{}; +template<class K> struct Map_taglist_to_typelist<K,typeset<> > : typeset<> {}; +} + +template<class List = typeset<> > +struct Object_converter { + typedef Object result_type; + template<class F> + result_type operator()(Object const& o, F const& f) const { + typedef typename List::head H; + if (H const* ptr = object_cast<H>(&o)) + return make_object(f(*ptr)); + else + return Object_converter<typename List::tail>()(o,f); + } +}; +template<> +struct Object_converter <typeset<> > { + typedef Object result_type; + template<class F> + 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 Final_, class K1, class K2, class List> +class KernelD_converter_ +: public KernelD_converter_<Final_,K1,K2,typename List::tail> +{ + typedef typename List::head Tag_; + typedef typename List::tail Rest; + typedef KernelD_converter_<Final_,K1,K2,Rest> Base; + typedef typename Get_type<K1,Tag_>::type K1_Obj; + typedef typename Get_type<K2,Tag_>::type K2_Obj; + typedef typename Get_functor<K1, Convert_ttag<Tag_> >::type K1_Conv; + typedef KO_converter<Tag_,K1,K2> KOC; + typedef CGAL_BOOSTD is_same<K1_Conv, Null_functor> no_converter; + typedef typename internal::Map_taglist_to_typelist<K1,Rest>::type::template contains<K1_Obj> 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_<boost::mpl::bool_<duplicate::value>, + // For iterator objects, the default is make_transforming_iterator + boost::mpl::bool_<(iterator_tag_traits<Tag_>::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<class X,int=0> struct result:Base::template result<X>{}; + template<int i> struct result<Final_(argument_type),i> {typedef K2_Obj type;}; +}; + +template<class Final_, class K1, class K2> +class KernelD_converter_<Final_,K1,K2,typeset<> > { + public: + struct Do_not_use2{}; + void operator()(Do_not_use2)const{} + template<class T> struct result; + Final_& myself(){return *static_cast<Final_*>(this);} + Final_ const& myself()const{return *static_cast<Final_ const*>(this);} +}; + + +// TODO: use the intersection of Kn::Object_list. +template<class K1, class K2, class List_= +typename typeset_intersection<typename K1::Object_list, typename K2::Object_list>::type +//typeset<Point_tag>::add<Vector_tag>::type/*::add<Segment_tag>::type*/ +> class KernelD_converter + : public Store_kernel<K1>, public Store_kernel2<K2>, + public KernelD_converter_<KernelD_converter<K1,K2,List_>,K1,K2,List_> +{ + typedef KernelD_converter Self; + typedef Self Final_; + typedef KernelD_converter_<Self,K1,K2,List_> Base; + typedef typename Get_type<K1, FT_tag>::type FT1; + typedef typename Get_type<K2, FT_tag>::type FT2; + typedef NT_converter<FT1, FT2> 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<K1>(a),Store_kernel2<K2>(b){} + + // For boost::result_of, used in transforming_iterator + template<class T,int i=is_iterator<T>::value?42:0> struct result:Base::template result<T>{}; + template<class T> struct result<Final_(T),42> { + typedef transforming_iterator<Final_,T> type; + }; + template<int i> struct result<Final_(K1),i>{typedef K2 type;}; + template<int i> struct result<Final_(int),i>{typedef int type;}; + // Ideally the next 2 would come with Point_tag and Vector_tag, but that's hard... + template<int i> struct result<Final_(Origin),i>{typedef Origin type;}; + template<int i> struct result<Final_(Null_vector),i>{typedef Null_vector type;}; + template<int i> struct result<Final_(Object),i>{typedef Object type;}; + template<int i> struct result<Final_(FT1),i>{typedef FT2 type;}; + + using Base::operator(); + typename Store_kernel2<K2>::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<RT1,FT1>::Type const&x)const{return cr(x);} + + typename Get_type<K2, Flat_orientation_tag>::type const& + operator()(typename Get_type<K1, Flat_orientation_tag>::type const&o)const + { return o; } // Both kernels should have the same, returning a reference should warn if not. + + template<class It> + transforming_iterator<Final_,typename boost::enable_if<is_iterator<It>,It>::type> + operator()(It const& it) const { + return make_transforming_iterator(it,*this); + } + + template<class T> + //TODO: use decltype in C++11 instead of result + std::vector<typename result<Final_(T)>::type> + operator()(const std::vector<T>& v) const { + return std::vector<typename result<Final_(T)>::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<K1,List_>::type Possibilities; + //TODO: add Empty, vector<Point>, etc to the list. + return Object_converter<Possibilities>()(obj,*this); + } + + //TODO: convert boost::variant + +}; + +} //namespace CGAL + +#endif // CGAL_KERNEL_D_CARTESIAN_CONVERTER_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_2_interface.h new file mode 100644 index 00000000..fa30dff0 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/utils.h> +#include <CGAL/tuple.h> + + +namespace CGAL { +template <class Base_> struct Kernel_2_interface : public Base_ { + typedef Base_ Base; + typedef Kernel_2_interface<Base> Kernel; + typedef typename Get_type<Base, RT_tag>::type RT; + typedef typename Get_type<Base, FT_tag>::type FT; + typedef typename Get_type<Base, Bool_tag>::type Boolean; + typedef typename Get_type<Base, Sign_tag>::type Sign; + typedef typename Get_type<Base, Comparison_result_tag>::type Comparison_result; + typedef typename Get_type<Base, Orientation_tag>::type Orientation; + typedef typename Get_type<Base, Oriented_side_tag>::type Oriented_side; + typedef typename Get_type<Base, Bounded_side_tag>::type Bounded_side; + typedef typename Get_type<Base, Angle_tag>::type Angle; + typedef typename Get_type<Base, Point_tag>::type Point_2; + typedef typename Get_type<Base, Vector_tag>::type Vector_2; + typedef typename Get_type<Base, Segment_tag>::type Segment_2; + typedef cpp0x::tuple<Point_2,Point_2,Point_2> Triangle_2; // triangulation insists... + template <class T,int i> struct Help_2p_i { + typedef typename Get_functor<Base, T>::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_point_cartesian_coordinate_tag,0> Less_x_2; + typedef Help_2p_i<Less_point_cartesian_coordinate_tag,1> Less_y_2; + typedef Help_2p_i<Compare_point_cartesian_coordinate_tag,0> Compare_x_2; + typedef Help_2p_i<Compare_point_cartesian_coordinate_tag,1> Compare_y_2; + struct Compare_distance_2 { + typedef typename Get_functor<Base, Compare_distance_tag>::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<Base, Orientation_of_points_tag>::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<Dereference_functor>(t+0),make_transforming_iterator<Dereference_functor>(t+3)); + + } + }; + struct Side_of_oriented_circle_2 { + typedef typename Get_functor<Base, Side_of_oriented_sphere_tag>::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<Dereference_functor>(t+0),make_transforming_iterator<Dereference_functor>(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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_3_interface.h new file mode 100644 index 00000000..96076aa8 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/utils.h> +#include <CGAL/tuple.h> + + +namespace CGAL { +template <class Base_> struct Kernel_3_interface : public Base_ { + typedef Base_ Base; + typedef Kernel_3_interface<Base> Kernel; + typedef typename Get_type<Base, RT_tag>::type RT; + typedef typename Get_type<Base, FT_tag>::type FT; + typedef typename Get_type<Base, Bool_tag>::type Boolean; + typedef typename Get_type<Base, Sign_tag>::type Sign; + typedef typename Get_type<Base, Comparison_result_tag>::type Comparison_result; + typedef typename Get_type<Base, Orientation_tag>::type Orientation; + typedef typename Get_type<Base, Oriented_side_tag>::type Oriented_side; + typedef typename Get_type<Base, Bounded_side_tag>::type Bounded_side; + typedef typename Get_type<Base, Angle_tag>::type Angle; + typedef typename Get_type<Base, Point_tag>::type Point_3; + typedef typename Get_type<Base, Vector_tag>::type Vector_3; + typedef typename Get_type<Base, Segment_tag>::type Segment_3; + typedef cpp0x::tuple<Point_3,Point_3,Point_3> Triangle_3; // placeholder + typedef cpp0x::tuple<Point_3,Point_3,Point_3,Point_3> Tetrahedron_3; // placeholder + struct Compare_xyz_3 { + typedef typename Get_functor<Base, Compare_lexicographically_tag>::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<Base, Compare_distance_tag>::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<Base, Orientation_of_points_tag>::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<Dereference_functor>(t+0),make_transforming_iterator<Dereference_functor>(t+4)); + + } + }; + struct Side_of_oriented_sphere_3 { + typedef typename Get_functor<Base, Side_of_oriented_sphere_tag>::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<Dereference_functor>(t+0),make_transforming_iterator<Dereference_functor>(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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_d_interface.h new file mode 100644 index 00000000..dd888005 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/utils.h> +#include <CGAL/tuple.h> + + +namespace CGAL { +template <class Base_> 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<Base> Kernel; + typedef Base_ R_; // for the macros + typedef typename Get_type<Base, RT_tag>::type RT; + typedef typename Get_type<Base, FT_tag>::type FT; + typedef typename Get_type<Base, Bool_tag>::type Boolean; + typedef typename Get_type<Base, Sign_tag>::type Sign; + typedef typename Get_type<Base, Comparison_result_tag>::type Comparison_result; + typedef typename Get_type<Base, Orientation_tag>::type Orientation; + typedef typename Get_type<Base, Oriented_side_tag>::type Oriented_side; + typedef typename Get_type<Base, Bounded_side_tag>::type Bounded_side; + typedef typename Get_type<Base, Angle_tag>::type Angle; + typedef typename Get_type<Base, Flat_orientation_tag>::type Flat_orientation_d; + typedef typename Get_type<Base, Point_tag>::type Point_d; + typedef typename Get_type<Base, Vector_tag>::type Vector_d; + typedef typename Get_type<Base, Segment_tag>::type Segment_d; + typedef typename Get_type<Base, Sphere_tag>::type Sphere_d; + typedef typename Get_type<Base, Hyperplane_tag>::type Hyperplane_d; + typedef Vector_d Direction_d; + typedef typename Get_type<Base, Line_tag>::type Line_d; + typedef typename Get_type<Base, Ray_tag>::type Ray_d; + typedef typename Get_type<Base, Iso_box_tag>::type Iso_box_d; + typedef typename Get_type<Base, Aff_transformation_tag>::type Aff_transformation_d; + typedef typename Get_type<Base, Weighted_point_tag>::type Weighted_point_d; + typedef typename Get_functor<Base, Compute_point_cartesian_coordinate_tag>::type Compute_coordinate_d; + typedef typename Get_functor<Base, Compare_lexicographically_tag>::type Compare_lexicographically_d; + typedef typename Get_functor<Base, Equal_points_tag>::type Equal_d; + typedef typename Get_functor<Base, Less_lexicographically_tag>::type Less_lexicographically_d; + typedef typename Get_functor<Base, Less_or_equal_lexicographically_tag>::type Less_or_equal_lexicographically_d; + // FIXME: and vectors? + typedef typename Get_functor<Base, Orientation_of_points_tag>::type Orientation_d; + typedef typename Get_functor<Base, Less_point_cartesian_coordinate_tag>::type Less_coordinate_d; + typedef typename Get_functor<Base, Point_dimension_tag>::type Point_dimension_d; + typedef typename Get_functor<Base, Side_of_oriented_sphere_tag>::type Side_of_oriented_sphere_d; + typedef typename Get_functor<Base, Power_side_of_power_sphere_tag>::type Power_side_of_power_sphere_d; + typedef typename Get_functor<Base, Power_center_tag>::type Power_center_d; + typedef typename Get_functor<Base, Power_distance_tag>::type Power_distance_d; + typedef typename Get_functor<Base, Contained_in_affine_hull_tag>::type Contained_in_affine_hull_d; + typedef typename Get_functor<Base, Construct_flat_orientation_tag>::type Construct_flat_orientation_d; + typedef typename Get_functor<Base, In_flat_orientation_tag>::type In_flat_orientation_d; + typedef typename Get_functor<Base, In_flat_side_of_oriented_sphere_tag>::type In_flat_side_of_oriented_sphere_d; + typedef typename Get_functor<Base, In_flat_power_side_of_power_sphere_tag>::type In_flat_power_side_of_power_sphere_d; + typedef typename Get_functor<Base, Point_to_vector_tag>::type Point_to_vector_d; + typedef typename Get_functor<Base, Vector_to_point_tag>::type Vector_to_point_d; + typedef typename Get_functor<Base, Translated_point_tag>::type Translated_point_d; + typedef typename Get_functor<Base, Scaled_vector_tag>::type Scaled_vector_d; + typedef typename Get_functor<Base, Difference_of_vectors_tag>::type Difference_of_vectors_d; + typedef typename Get_functor<Base, Difference_of_points_tag>::type Difference_of_points_d; + //typedef typename Get_functor<Base, Construct_ttag<Point_tag> >::type Construct_point_d; + struct Construct_point_d : private Store_kernel<Kernel> { + typedef Kernel R_; // for the macro + CGAL_FUNCTOR_INIT_STORE(Construct_point_d) + typedef typename Get_functor<Base, Construct_ttag<Point_tag> >::type CP; + typedef Point_d result_type; + Point_d operator()(Weighted_point_d const&wp)const{ + return typename Get_functor<Base, Point_drop_weight_tag>::type(this->kernel())(wp); + } +#ifdef CGAL_CXX11 + Point_d operator()(Weighted_point_d &wp)const{ + return typename Get_functor<Base, Point_drop_weight_tag>::type(this->kernel())(wp); + } + Point_d operator()(Weighted_point_d &&wp)const{ + return typename Get_functor<Base, Point_drop_weight_tag>::type(this->kernel())(std::move(wp)); + } + Point_d operator()(Weighted_point_d const&&wp)const{ + return typename Get_functor<Base, Point_drop_weight_tag>::type(this->kernel())(std::move(wp)); + } + template<class...T> +# if __cplusplus >= 201402L + decltype(auto) +# else + Point_d +# endif + operator()(T&&...t)const{ + return CP(this->kernel())(std::forward<T>(t)...); + //return CP(this->kernel())(t...); + } +#else +# define CGAL_CODE(Z,N,_) template<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<Base, Construct_ttag<Vector_tag> >::type Construct_vector_d; + typedef typename Get_functor<Base, Construct_ttag<Segment_tag> >::type Construct_segment_d; + typedef typename Get_functor<Base, Construct_ttag<Sphere_tag> >::type Construct_sphere_d; + typedef typename Get_functor<Base, Construct_ttag<Hyperplane_tag> >::type Construct_hyperplane_d; + typedef Construct_vector_d Construct_direction_d; + typedef typename Get_functor<Base, Construct_ttag<Line_tag> >::type Construct_line_d; + typedef typename Get_functor<Base, Construct_ttag<Ray_tag> >::type Construct_ray_d; + typedef typename Get_functor<Base, Construct_ttag<Iso_box_tag> >::type Construct_iso_box_d; + typedef typename Get_functor<Base, Construct_ttag<Aff_transformation_tag> >::type Construct_aff_transformation_d; + typedef typename Get_functor<Base, Construct_ttag<Weighted_point_tag> >::type Construct_weighted_point_d; + typedef typename Get_functor<Base, Midpoint_tag>::type Midpoint_d; + struct Component_accessor_d : private Store_kernel<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<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_cartesian_const_iterator_d) + typedef typename Get_functor<Base, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CPI; + typedef typename Get_functor<Base, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<typename boost::result_of<CPI(Point_d,CGAL::Begin_tag)>::type>::type result_type; + typedef typename CGAL::decay<typename CPI::result_type>::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<typename CGAL::decay<typename boost::result_of<CVI(Vector_d,CGAL::Begin_tag)>::type>::type, result_type>::value)); + CGAL_static_assertion((boost::is_same<typename CGAL::decay<typename CVI::result_type>::type, result_type>::value)); + template <class Tag_> + result_type operator()(Point_d const&p, Tag_ t)const{ + return CPI(this->kernel())(p,t); + } + template <class Tag_> + result_type operator()(typename First_if_different<Vector_d,Point_d>::Type const&v, Tag_ t)const{ + return CVI(this->kernel())(v,t); + } + + template <class Obj> + 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<Vector_d,Point_d>::Type const&v, int)const{ + return operator()(v, End_tag()); + } + }; + struct Compute_squared_radius_d : private Store_kernel<Kernel> { + typedef Kernel R_; // for the macro + CGAL_FUNCTOR_INIT_STORE(Compute_squared_radius_d) + typedef FT result_type; + template<class S> FT operator()(CGAL_FORWARDABLE(S) s)const{ + return typename Get_functor<Base, Squared_radius_tag>::type(this->kernel())(CGAL_FORWARD(S,s)); + } + template<class I> FT operator()(I b, I e)const{ + return typename Get_functor<Base, Squared_circumradius_tag>::type(this->kernel())(b,e); + } + }; + typedef typename Construct_cartesian_const_iterator_d::result_type Cartesian_const_iterator_d; + typedef typename Get_functor<Base, Squared_distance_tag>::type Squared_distance_d; + typedef typename Get_functor<Base, Squared_length_tag>::type Squared_length_d; + typedef typename Get_functor<Base, Scalar_product_tag>::type Scalar_product_d; + typedef typename Get_functor<Base, Affine_rank_tag>::type Affine_rank_d; + typedef typename Get_functor<Base, Affinely_independent_tag>::type Affinely_independent_d; + typedef typename Get_functor<Base, Contained_in_linear_hull_tag>::type Contained_in_linear_hull_d; + typedef typename Get_functor<Base, Contained_in_simplex_tag>::type Contained_in_simplex_d; + typedef typename Get_functor<Base, Has_on_positive_side_tag>::type Has_on_positive_side_d; + typedef typename Get_functor<Base, Linear_rank_tag>::type Linear_rank_d; + typedef typename Get_functor<Base, Linearly_independent_tag>::type Linearly_independent_d; + typedef typename Get_functor<Base, Oriented_side_tag>::type Oriented_side_d; + typedef typename Get_functor<Base, Side_of_bounded_circumsphere_tag>::type Side_of_bounded_sphere_d; + + typedef typename Get_functor<Base, Center_of_sphere_tag>::type Center_of_sphere_d; + typedef Center_of_sphere_d Construct_center_d; // RangeSearchTraits + typedef typename Get_functor<Base, Construct_circumcenter_tag>::type Construct_circumcenter_d; + typedef typename Get_functor<Base, Value_at_tag>::type Value_at_d; + typedef typename Get_functor<Base, Point_of_sphere_tag>::type Point_of_sphere_d; + typedef typename Get_functor<Base, Orthogonal_vector_tag>::type Orthogonal_vector_d; + typedef typename Get_functor<Base, Linear_base_tag>::type Linear_base_d; + typedef typename Get_functor<Base, Construct_min_vertex_tag>::type Construct_min_vertex_d; + typedef typename Get_functor<Base, Construct_max_vertex_tag>::type Construct_max_vertex_d; + + typedef typename Get_functor<Base, Point_weight_tag>::type Compute_weight_d; + typedef typename Get_functor<Base, Point_drop_weight_tag>::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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Kernel_object_converter.h new file mode 100644 index 00000000..99918ed2 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/utils.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Kernel/mpl.h> // First_if_different +#include <CGAL/Dimension.h> +namespace CGAL { +template <class Tag_, class K1, class K2> 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 <class D /*=Dynamic_dimension_tag*/, class K1, class K2> +struct Point_converter_help { + typedef typename Get_type<K1, Point_tag>::type argument_type; + typedef typename Get_type<K2, Point_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + typename Get_functor<K1, Construct_ttag<Point_cartesian_const_iterator_tag> >::type i(k1); + typename Get_functor<K2, Construct_ttag<Point_tag> >::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 <int d, class K1, class K2> +struct Point_converter_help<Dimension_tag<d>,K1,K2> { + typedef typename Get_type<K1, Point_tag>::type argument_type; + typedef typename Get_type<K2, Point_tag>::type result_type; + template <class C,int...I> + result_type help(Indices<I...>, K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + typename Get_functor<K1, Compute_point_cartesian_coordinate_tag>::type cc(k1); + typename Get_functor<K2, Construct_ttag<Point_tag> >::type cp(k2); + return cp(conv(cc(p,I))...); + } + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& p) const { + return help(typename N_increasing_indices<d>::type(),k1,k2,conv,p); + } +}; +#endif +} +template <class K1, class K2> struct KO_converter<Point_tag,K1,K2> +: internal::Point_converter_help<typename K1::Default_ambient_dimension,K1,K2> +{}; + +template <class K1, class K2> struct KO_converter<Vector_tag,K1,K2>{ + typedef typename Get_type<K1, Vector_tag>::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<K1_Vector,K1_Point>::Type argument_type; + + typedef K1_Vector argument_type; + typedef typename Get_type<K2, Vector_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& v) const { + typename Get_functor<K1, Construct_ttag<Vector_cartesian_const_iterator_tag> >::type i(k1); + typename Get_functor<K2, Construct_ttag<Vector_tag> >::type cp(k2); + return cp(conv(i(v,Begin_tag())),conv(i(v,End_tag()))); + } +}; + +template <class K1, class K2> struct KO_converter<Segment_tag,K1,K2>{ + typedef typename Get_type<K1, Segment_tag>::type argument_type; + typedef typename Get_type<K2, Segment_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor<K1, Segment_extremity_tag>::type f(k1); + typename Get_functor<K2, Construct_ttag<Segment_tag> >::type cs(k2); + return cs(conv(f(s,0)),conv(f(s,1))); + } +}; + +template <class K1, class K2> struct KO_converter<Hyperplane_tag,K1,K2>{ + typedef typename Get_type<K1, Hyperplane_tag>::type argument_type; + typedef typename Get_type<K2, Hyperplane_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& h) const { + typename Get_functor<K1, Orthogonal_vector_tag>::type ov(k1); + typename Get_functor<K1, Hyperplane_translation_tag>::type ht(k1); + typename Get_functor<K2, Construct_ttag<Hyperplane_tag> >::type ch(k2); + return ch(conv(ov(h)),conv(ht(h))); + } +}; + +template <class K1, class K2> struct KO_converter<Sphere_tag,K1,K2>{ + typedef typename Get_type<K1, Sphere_tag>::type argument_type; + typedef typename Get_type<K2, Sphere_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor<K1, Center_of_sphere_tag>::type cos(k1); + typename Get_functor<K1, Squared_radius_tag>::type sr(k1); + typename Get_functor<K2, Construct_ttag<Sphere_tag> >::type cs(k2); + return cs(conv(cos(s)),conv(sr(s))); + } +}; + +template <class K1, class K2> struct KO_converter<Weighted_point_tag,K1,K2>{ + typedef typename Get_type<K1, Weighted_point_tag>::type argument_type; + typedef typename Get_type<K2, Weighted_point_tag>::type result_type; + template <class C> + result_type operator()(K1 const& k1, K2 const& k2, C const& conv, argument_type const& s) const { + typename Get_functor<K1, Point_drop_weight_tag>::type pdw(k1); + typename Get_functor<K1, Point_weight_tag>::type pw(k1); + typename Get_functor<K2, Construct_ttag<Weighted_point_tag> >::type cwp(k2); + return cwp(conv(pdw(s)),conv(pw(s))); + } +}; + +} +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/LA.h new file mode 100644 index 00000000..ddbdc37b --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#ifndef CGAL_EIGEN3_ENABLED +#error Requires Eigen +#endif +#include <boost/type_traits/is_arithmetic.hpp> +#include <boost/utility/enable_if.hpp> +#include <CGAL/Dimension.h> +#include <Eigen/Dense> +#include <CGAL/NewKernel_d/LA_eigen/constructors.h> +#include <CGAL/iterator_from_indices.h> + +namespace CGAL { + +//FIXME: where could we use Matrix_base instead of Matrix? +// Dim_ real dimension +// Max_dim_ upper bound on the dimension +template<class NT_,class Dim_,class Max_dim_=Dim_> struct LA_eigen { + typedef NT_ NT; + typedef Dim_ Dimension; + typedef Max_dim_ Max_dimension; + enum { dimension = Eigen_dimension<Dimension>::value }; + enum { max_dimension = Eigen_dimension<Max_dimension>::value }; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef LA_eigen< NT, D2, D3 > Other; + }; + template<class,class=void> struct Property : boost::false_type {}; + template<class D> struct Property<Has_vector_plus_minus_tag,D> : boost::true_type {}; + template<class D> struct Property<Has_vector_scalar_ops_tag,D> : boost::true_type {}; + template<class D> struct Property<Has_dot_product_tag,D> : boost::true_type {}; + + typedef Eigen::Matrix<NT,Eigen_dimension<Dim_>::value,1,Eigen::ColMajor|Eigen::AutoAlign,Eigen_dimension<Max_dim_>::value,1> Vector; + typedef Eigen::Matrix<NT,Eigen::Dynamic,1> Dynamic_vector; + typedef Construct_eigen<Vector> Construct_vector; + +#if (EIGEN_WORLD_VERSION>=3) + typedef NT const* Vector_const_iterator; +#else + typedef Iterator_from_indices<const type,const NT +#ifndef CGAL_CXX11 + ,NT +#endif + > Vector_const_iterator; +#endif + + template<class Vec_>static Vector_const_iterator vector_begin(Vec_ const&a){ +#if (EIGEN_WORLD_VERSION>=3) + return &a[0]; +#else + return Vector_const_iterator(a,0); +#endif + } + + template<class Vec_>static 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<NT,dimension,dimension,Eigen::ColMajor|Eigen::AutoAlign,max_dimension,max_dimension> Square_matrix; + typedef Eigen::Matrix<NT,dimension,Eigen::Dynamic,Eigen::ColMajor|Eigen::AutoAlign,max_dimension,Eigen::Dynamic> Dynamic_matrix; + //TODO: don't pass on the values of Max_* for an expensive NT + // typedef ... Constructor + // typedef ... Accessor +#if 0 + private: + template <class T> class Canonicalize_vector { + typedef typename Dimension_eigen<T::SizeAtCompileTime>::type S1; + typedef typename Dimension_eigen<T::MaxSizeAtCompileTime>::type S2; + public: + typedef typename Vector<S1,S2>::type type; + }; + public: +#endif + + template<class Vec_>static int size_of_vector(Vec_ const&v){ + return (int)v.size(); + } + + template<class Vec_>static NT dot_product(Vec_ const&a,Vec_ const&b){ + return a.dot(b); + } + + template<class Vec_> static int rows(Vec_ const&v) { + return (int)v.rows(); + } + template<class Vec_> static int columns(Vec_ const&v) { + return (int)v.cols(); + } + + template<class Mat_> static NT determinant(Mat_ const&m,bool=false){ + return m.determinant(); + } + + template<class Mat_> static typename + Same_uncertainty_nt<CGAL::Sign, NT>::type + sign_of_determinant(Mat_ const&m,bool=false) + { + return CGAL::sign(m.determinant()); + } + + template<class Mat_> 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<Mat_> decomp(m); + Eigen::FullPivLU<Mat_> decomp(m); + // decomp.setThreshold(0); + return static_cast<int>(decomp.rank()); + } + + // m*a==b + template<class DV, class DM, class V> + static void solve(DV&a, DM const&m, V const& b){ + //a = m.colPivHouseholderQr().solve(b); + a = m.fullPivLu().solve(b); + } + template<class DV, class DM, class V> + 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<class Vec1,class Vec2> 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<class Vec1,class Vec2> 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<class Vec1,class Vec2> static std::pair<NT,NT> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/LA_eigen/constructors.h new file mode 100644 index 00000000..3636996f --- /dev/null +++ b/src/common/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 <CGAL/config.h> + +#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 <boost/type_traits/is_arithmetic.hpp> +#include <boost/utility/enable_if.hpp> +#include <CGAL/Dimension.h> +#include <Eigen/Dense> +#include <CGAL/iterator_from_indices.h> +#include <CGAL/NewKernel_d/utils.h> +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/repetition/enum.hpp> +#include <boost/preprocessor/repetition/enum_params.hpp> + +namespace CGAL { + template <class Vector_> 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<typename Iter> + 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<typename Iter> + 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<typename Iter,typename T> + 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<class T> + result_type operator()(std::initializer_list<T> 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<class...U> + result_type operator()(U&&...u) const { + check_dim(sizeof...(U)); // TODO: use static_assert + return Initializer_list()({forward_safe<NT,U>(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<class H,class...U> + result_type operator()(H const&h,U&&...u) const { + check_dim(sizeof...(U)); // TODO: use static_assert + return Initializer_list()({Rational_traits<NT>().make_rational(std::forward<U>(u),h)...}); + } +#else + +#define CGAL_VAR(Z,N,_) ( Rational_traits<NT>().make_rational( t##N ,h) ) +#define CGAL_CODE(Z,N,_) template <class H> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Lazy_cartesian.h new file mode 100644 index 00000000..9ecc2b63 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/algorithm.h> +#include <CGAL/Lazy.h> +#include <CGAL/Default.h> +#include <CGAL/NewKernel_d/Filtered_predicate2.h> +#include <CGAL/iterator_from_indices.h> +#include <CGAL/NewKernel_d/Define_kernel_types.h> + +namespace CGAL { + +template<class K,class T> +struct Nth_iterator_element : private Store_kernel<K> { + Nth_iterator_element(){} + Nth_iterator_element(K const&k):Store_kernel<K>(k){} + typedef typename Get_type<K, typename iterator_tag_traits<T>::value_tag>::type result_type; + template<class U> result_type operator()(CGAL_FORWARDABLE(U) u, int i) const { + typename Get_functor<K, Construct_ttag<T> >::type ci(this->kernel()); + return *cpp0x::next(ci(CGAL_FORWARD(U,u),Begin_tag()),i); + } +}; + //typedef typename Functor<typename iterator_tag_traits<T>::nth_element>::type nth_elem; +template<class K, class T, bool = iterator_tag_traits<T>::has_nth_element> +struct Select_nth_element_functor { + typedef Nth_iterator_element<K, T> type; +}; +template<class K, class T> +struct Select_nth_element_functor <K, T, true> : + Get_functor<K, typename iterator_tag_traits<T>::nth_element> {}; + +namespace internal { + template<class A,class B,class C,bool/*is_NT=false*/> + struct Lazy_construction_maybe_nt { + typedef Lazy_construction<A,B,C> type; + }; + template<class A,class B,class C> + struct Lazy_construction_maybe_nt<A,B,C,true> { + typedef Lazy_construction_nt<A,B,C> type; + }; +} + +template <class EK_, class AK_, class E2A_, class Kernel_> +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 <class T,class=typename Get_type_category<Kernel_,T>::type> struct Type {}; + template <class T> struct Type<T,Object_tag> { + typedef Lazy< + typename Get_type<AK_,T>::type, + typename Get_type<EK_,T>::type, + typename Get_type<EK_, FT_tag>::type, + E2A_> type; + }; + template <class T> struct Type<T,Number_tag> { + typedef CGAL::Lazy_exact_nt<typename Get_type<EK_,T>::type> type; + }; + + template <class T> struct Iterator { + typedef typename iterator_tag_traits<T>::value_tag Vt; + typedef typename Type<Vt>::type V; + typedef typename Select_nth_element_functor<AK_,T>::type AF; + typedef typename Select_nth_element_functor<EK_,T>::type EF; + + typedef typename internal::Lazy_construction_maybe_nt< + Kernel_, AF, EF, is_NT_tag<Vt>::value + >::type nth_elem; + + typedef Iterator_from_indices< + const typename Type<typename iterator_tag_traits<T>::container>::type, + const V, V, nth_elem + > type; + }; +}; + +template <class EK_, class AK_, class E2A_/*, class Kernel_=Default*/> +struct Lazy_cartesian : Dimension_base<typename EK_::Default_ambient_dimension>, + Lazy_cartesian_types<EK_,AK_,E2A_,Lazy_cartesian<EK_,AK_,E2A_> > +{ + //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<EK_,AK_,E2A_,Self> Base; + //typedef typename Default::Get<Kernel_,Self>::type Kernel; + typedef Self Kernel; + typedef AK_ Approximate_kernel; + typedef EK_ Exact_kernel; + typedef E2A_ E2A; + typedef Approx_converter<Kernel, Approximate_kernel> C2A; + typedef Exact_converter<Kernel, Exact_kernel> 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<class T,class D=void,class=typename Get_functor_category<Lazy_cartesian,T,D>::type> struct Functor { + typedef Null_functor type; + }; + //FIXME: what do we do with D here? + template<class T,class D> struct Functor<T,D,Predicate_tag> { + typedef typename Get_functor<Approximate_kernel, T>::type FA; + typedef typename Get_functor<Exact_kernel, T>::type FE; + typedef Filtered_predicate2<FE,FA,C2E,C2A> type; + }; + template<class T,class D> struct Functor<T,D,Compute_tag> { + typedef typename Get_functor<Approximate_kernel, T>::type FA; + typedef typename Get_functor<Exact_kernel, T>::type FE; + typedef Lazy_construction_nt<Kernel,FA,FE> type; + }; + template<class T,class D> struct Functor<T,D,Construct_tag> { + typedef typename Get_functor<Approximate_kernel, T>::type FA; + typedef typename Get_functor<Exact_kernel, T>::type FE; + typedef Lazy_construction<Kernel,FA,FE> type; + }; + + //typedef typename Iterator<Point_cartesian_const_iterator_tag>::type Point_cartesian_const_iterator; + //typedef typename Iterator<Vector_cartesian_const_iterator_tag>::type Vector_cartesian_const_iterator; + + template<class U> + struct Construct_iter : private Store_kernel<Kernel> { + Construct_iter(){} + Construct_iter(Kernel const&k):Store_kernel<Kernel>(k){} + //FIXME: pass the kernel to the functor in the iterator + typedef U result_type; + template<class T> + result_type operator()(T const& t,Begin_tag)const{ + return result_type(t,0,this->kernel()); + } + template<class T> + result_type operator()(T const& t,End_tag)const{ + return result_type(t,Self().dimension(),this->kernel()); + } + }; + template<class T,class D> struct Functor<T,D,Construct_iterator_tag> { + typedef Construct_iter<typename Base::template Iterator<typename map_result_tag<T>::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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Aff_transformation.h new file mode 100644 index 00000000..6d9f070f --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <boost/preprocessor/repetition.hpp> + +// Dummy, that's all the Kernel_d concept requires, so a useful class will wait. + +namespace CGAL { +template<class R_> +struct Aff_transformation { + typedef R_ R; +}; +namespace CartesianDKernelFunctors { +template<class R_> struct Construct_aff_transformation { + CGAL_FUNCTOR_INIT_IGNORE(Construct_aff_transformation) + typedef R_ R; + typedef typename Get_type<R, Aff_transformation_tag>::type result_type; +#ifdef CGAL_CXX11 + template<class...T> + result_type operator()(T&&...)const{return result_type();} +#else + result_type operator()()const{ + return result_type(); + } +#define CGAL_CODE(Z,N,_) template<BOOST_PP_ENUM_PARAMS(N,class U)> \ + 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<K>),(),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Aff_transformation_tag>,(CartesianDKernelFunctors::Construct_aff_transformation<K>),(Aff_transformation_tag),()); + +} +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Hyperplane.h new file mode 100644 index 00000000..14e35b01 --- /dev/null +++ b/src/common/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 <CGAL/enum.h> +#include <CGAL/number_utils.h> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +namespace CGAL { +template <class R_> class Hyperplane { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Vector_tag>::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 <class R_> struct Construct_hyperplane : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_hyperplane) + typedef typename Get_type<R_, Hyperplane_tag>::type result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Vector_tag>::type Vector; + typedef typename Get_type<R_, FT_tag>::type FT; + private: + struct One { + typedef int result_type; + template<class T>int 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<R_, Construct_ttag<Vector_tag> >::type cv(this->kernel()); + return result_type(cv(),0); + } + + template <class Iter> + 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<D1>::type D1i; + typedef typename Increment_dimension<D2>::type D2i; + + typedef Eigen::Matrix<FT, Eigen_dimension<D1>::value, Eigen_dimension<D1i>::value, + Eigen::ColMajor|Eigen::AutoAlign, Eigen_dimension<D2>::value, Eigen_dimension<D2i>::value> Matrix; + typedef Eigen::Matrix<FT, Eigen_dimension<D1i>::value, 1, + Eigen::ColMajor|Eigen::AutoAlign, Eigen_dimension<D2i>::value, 1> Vec; + typename Get_functor<R_, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R_, Construct_ttag<Vector_tag> >::type cv(this->kernel()); + typename Get_functor<R_, Point_dimension_tag>::type pd(this->kernel()); + + Point const& p0=*f; + int d = pd(p0); + Matrix m(d,d+1); + for(int j=0;j<d;++j) + m(0,j)=c(p0,j); + // Write the point coordinates in lines. + int i; + for (i=1; ++f!=e; ++i) { + Point const& p=*f; + for(int j=0;j<d;++j) + m(i,j)=c(p,j); + } + CGAL_assertion (i == d); + for(i=0;i<d;++i) + m(i,d)=-1; + Eigen::FullPivLU<Matrix> 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 <class Iter> + 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<R_, Oriented_side_tag>::type os(this->kernel()); + CGAL::Oriented_side o = os(ret, p); + if (o == ON_ORIENTED_BOUNDARY || o == s) + return ret; + typename Get_functor<R_, Opposite_vector_tag>::type ov(this->kernel()); + typename Get_functor<R_, Construct_ttag<Vector_tag> >::type cv(this->kernel()); + return this->operator()(ov(ret.orthogonal_vector()), -ret.translation()); + } +}; +template <class R_> struct Orthogonal_vector { + CGAL_FUNCTOR_INIT_IGNORE(Orthogonal_vector) + typedef typename Get_type<R_, Hyperplane_tag>::type Hyperplane; + typedef typename Get_type<R_, Vector_tag>::type const& result_type; + result_type operator()(Hyperplane const&s)const{ + return s.orthogonal_vector(); + } +}; +template <class R_> struct Hyperplane_translation { + CGAL_FUNCTOR_INIT_IGNORE(Hyperplane_translation) + typedef typename Get_type<R_, Hyperplane_tag>::type Hyperplane; + typedef typename Get_type<R_, FT_tag>::type result_type; + // TODO: Is_exact? + result_type operator()(Hyperplane const&s)const{ + return s.translation(); + } +}; +template <class R_> struct Value_at : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Value_at) + typedef typename Get_type<R_, Hyperplane_tag>::type Hyperplane; + typedef typename Get_type<R_, Vector_tag>::type Vector; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, FT_tag>::type FT; + typedef FT result_type; + typedef typename Get_functor<R_, Scalar_product_tag>::type Dot; + typedef typename Get_functor<R_, Point_to_vector_tag>::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<K>),(Vector_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Hyperplane_tag>,(CartesianDKernelFunctors::Construct_hyperplane<K>),(Vector_tag,Hyperplane_tag),(Opposite_vector_tag,Oriented_side_tag)); +CGAL_KD_DEFAULT_FUNCTOR(Orthogonal_vector_tag,(CartesianDKernelFunctors::Orthogonal_vector<K>),(Vector_tag,Hyperplane_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Hyperplane_translation_tag,(CartesianDKernelFunctors::Hyperplane_translation<K>),(Hyperplane_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Value_at_tag,(CartesianDKernelFunctors::Value_at<K>),(Point_tag,Vector_tag,Hyperplane_tag),(Scalar_product_tag,Point_to_vector_tag)); +} // namespace CGAL +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Iso_box.h new file mode 100644 index 00000000..d053f351 --- /dev/null +++ b/src/common/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 <utility> +#include <CGAL/basic.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/transforming_pair_iterator.h> +namespace CGAL { +template <class R_> class Iso_box { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef std::pair<Point_,Point_> 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 <class R_> struct Construct_iso_box : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_iso_box) + typedef typename Get_type<R_, Iso_box_tag>::type result_type; + typedef typename Get_type<R_, RT_tag>::type RT; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_functor<R_, Construct_ttag<Point_tag> >::type Cp_; + typedef typename Get_functor<R_, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<RT>()), + make_transforming_pair_iterator(ci(a,End_tag()), ci(b,End_tag()), Min<RT>())), + cp( + make_transforming_pair_iterator(ci(a,Begin_tag()), ci(b,Begin_tag()), Max<RT>()), + make_transforming_pair_iterator(ci(a,End_tag()), ci(b,End_tag()), Max<RT>()))); + } + }; + + template <class R_> struct Construct_min_vertex { + CGAL_FUNCTOR_INIT_IGNORE(Construct_min_vertex) + typedef typename Get_type<R_, Iso_box_tag>::type argument_type; + //TODO: make result_type a reference + typedef typename Get_type<R_, Point_tag>::type result_type; + result_type operator()(argument_type const&b)const{ + return b.min BOOST_PREVENT_MACRO_SUBSTITUTION (); + } + }; + template <class R_> struct Construct_max_vertex { + CGAL_FUNCTOR_INIT_IGNORE(Construct_max_vertex) + typedef typename Get_type<R_, Iso_box_tag>::type argument_type; + typedef typename Get_type<R_, Point_tag>::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<K>),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Iso_box_tag>,(CartesianDKernelFunctors::Construct_iso_box<K>),(Iso_box_tag,Point_tag),(Construct_ttag<Point_cartesian_const_iterator_tag>,Construct_ttag<Point_tag>)); +CGAL_KD_DEFAULT_FUNCTOR(Construct_min_vertex_tag,(CartesianDKernelFunctors::Construct_min_vertex<K>),(Iso_box_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_max_vertex_tag,(CartesianDKernelFunctors::Construct_max_vertex<K>),(Iso_box_tag),()); +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_ISO_BOX_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Line.h new file mode 100644 index 00000000..6a09571c --- /dev/null +++ b/src/common/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 <utility> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Kernel/mpl.h> +namespace CGAL { +template <class R_> class Line { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef std::pair<Point_,Point_> 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 <class R_> struct Construct_line : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_line) + typedef typename Get_type<R_, Line_tag>::type result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Vector_tag>::type Vector; + typedef typename Get_functor<R_, Translated_point_tag>::type Tp_; + //typedef typename Get_functor<R_, Difference_of_points_tag>::type Dp_; + //typedef typename Get_functor<R_, Scaled_vector_tag>::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<Vector,Point>::Type const&b)const{ + Tp_ tp(this->kernel()); + return result_type(a,tp(a,b)); + } + }; +} +CGAL_KD_DEFAULT_TYPE(Line_tag,(CGAL::Line<K>),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Line_tag>,(CartesianDKernelFunctors::Construct_line<K>),(Line_tag,Point_tag,Vector_tag),(Translated_point_tag)); + +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_LINE_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Ray.h new file mode 100644 index 00000000..be845e76 --- /dev/null +++ b/src/common/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 <utility> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Kernel/mpl.h> +namespace CGAL { +template <class R_> class Ray { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef typename Get_type<R_, Vector_tag>::type Vector_; + typedef std::pair<Point_,Vector_> 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 <class R_> struct Construct_ray : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_ray) + typedef typename Get_type<R_, Ray_tag>::type result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Vector_tag>::type Vector; + typedef typename Get_functor<R_, Difference_of_points_tag>::type Dp_; + //typedef typename Get_functor<R_, Translated_point_tag>::type Tp_; + //typedef typename Get_functor<R_, Scaled_vector_tag>::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<Point,Vector>::Type const&b)const{ + Dp_ dp(this->kernel()); + return result_type(a,dp(b,a)); + } + }; +} +CGAL_KD_DEFAULT_TYPE(Ray_tag,(CGAL::Ray<K>),(Point_tag,Vector_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Ray_tag>,(CartesianDKernelFunctors::Construct_ray<K>),(Point_tag,Ray_tag,Vector_tag),(Difference_of_points_tag)); + +} // namespace CGAL + +#endif // CGAL_KERNELD_TYPES_RAY_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Segment.h new file mode 100644 index 00000000..38361c2b --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#include <utility> +#include <CGAL/NewKernel_d/functor_tags.h> +namespace CGAL { +template <class R_> class Segment { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::type Point_; + //typedef typename R_::Vector Vector_; + //typedef typename Get_functor<R_, Construct_ttag<Vector_tag> >::type Cv_; +// typedef typename R_::Squared_distance Csd_; + typedef std::pair<Point_,Point_> Data_; + Data_ data; + public: + //typedef Segmentd<R_> Segment; +#ifdef CGAL_CXX11 + //FIXME: don't forward directly, piecewise_constuct should call the point construction functor (I guess? or is it unnecessary?) + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Segment>>::value>::type> + Segment(U&&...u):data(std::forward<U>(u)...){} +#else + Segment(){} + Segment(Point_ const&a, Point_ const&b): data(a,b) {} + //template<class A,class T1,class T2> + //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<class R_> struct Construct_segment : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_segment) + typedef R_ R; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Segment_tag>::type Segment; + typedef typename Get_functor<R_, Construct_ttag<Point_tag> >::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<R_, Construct_ttag<Point_tag> >::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<class T,class U,class V> + 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<Point>(cp, CGAL_FORWARD(U,u)), + call_on_tuple_elements<Point>(cp, CGAL_FORWARD(V,v)) }}; + return r; + } +}; + +// This should be part of Construct_point, according to Kernel_23 conventions +template<class R_> struct Segment_extremity { + CGAL_FUNCTOR_INIT_IGNORE(Segment_extremity) + typedef R_ R; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, Segment_tag>::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<K>),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Segment_tag>,(CartesianDKernelFunctors::Construct_segment<K>),(Segment_tag,Point_tag),(Construct_ttag<Point_tag>)); +CGAL_KD_DEFAULT_FUNCTOR(Segment_extremity_tag,(CartesianDKernelFunctors::Segment_extremity<K>),(Segment_tag,Point_tag),()); + +} // namespace CGAL + +#endif // CGAL_KERNELD_SEGMENTD_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Sphere.h new file mode 100644 index 00000000..114410b4 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/store_kernel.h> +#include <boost/iterator/counting_iterator.hpp> +namespace CGAL { +template <class R_> class Sphere { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::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 <class R_> struct Construct_sphere : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_sphere) + typedef typename Get_type<R_, Sphere_tag>::type result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, FT_tag>::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<R_, Construct_ttag<Point_tag> >::type cp(this->kernel()); + return result_type(cp(),0); + } + template <class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R_, Construct_circumcenter_tag>::type cc(this->kernel()); + typename Get_functor<R_, Squared_distance_tag>::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 <class R_> struct Center_of_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Center_of_sphere) + typedef typename Get_type<R_, Sphere_tag>::type Sphere; + // No reference because of the second overload + typedef typename Get_type<R_, Point_tag>::type result_type; + + result_type const& operator()(Sphere const&s)const{ + return s.center(); + } + + template<class Iter> + result_type operator()(Iter b, Iter e)const{ + typename Get_functor<R_, Construct_ttag<Sphere_tag> >::type cs(this->kernel()); + return operator()(cs(b,e)); // computes the radius needlessly + } +}; + +template <class R_> struct Squared_radius { + CGAL_FUNCTOR_INIT_IGNORE(Squared_radius) + typedef typename Get_type<R_, Sphere_tag>::type Sphere; + typedef typename Get_type<R_, FT_tag>::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<class R_> struct Point_of_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Point_of_sphere) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Sphere_tag>::type Sphere; + typedef typename Get_functor<R, Construct_ttag<Point_tag> >::type CP; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CI; + typedef typename Get_functor<R, Point_dimension_tag>::type PD; + typedef Point result_type; + typedef Sphere first_argument_type; + typedef int second_argument_type; + struct Trans : std::binary_function<FT,int,FT> { + 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<int,std::random_access_iterator_tag> 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<K>),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Sphere_tag>,(CartesianDKernelFunctors::Construct_sphere<K>),(Sphere_tag,Point_tag),(Construct_ttag<Point_tag>,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<K>),(Sphere_tag,Point_tag),(Construct_ttag<Sphere_tag>)); +CGAL_KD_DEFAULT_FUNCTOR(Squared_radius_tag,(CartesianDKernelFunctors::Squared_radius<K>),(Sphere_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_of_sphere_tag,(CartesianDKernelFunctors::Point_of_sphere<K>),(Sphere_tag,Point_tag),(Construct_ttag<Point_tag>, Construct_ttag<Point_cartesian_const_iterator_tag>)); +} // namespace CGAL +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Types/Weighted_point.h new file mode 100644 index 00000000..1caf8701 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/store_kernel.h> +#include <boost/iterator/counting_iterator.hpp> +namespace CGAL { +namespace KerD { +template <class R_> class Weighted_point { + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename Get_type<R_, Point_tag>::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 <class R_> struct Construct_weighted_point : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_weighted_point) + typedef typename Get_type<R_, Weighted_point_tag>::type result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, FT_tag>::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<R_, Construct_ttag<Point_tag> >::type cp(this->kernel()); + return result_type(cp(),0); + } +}; + +template <class R_> struct Point_drop_weight { + CGAL_FUNCTOR_INIT_IGNORE(Point_drop_weight) + typedef typename Get_type<R_, Weighted_point_tag>::type argument_type; + typedef typename Get_type<R_, Point_tag>::type const& result_type; + // Returning a reference is fragile + + result_type operator()(argument_type const&s)const{ + return s.point(); + } +}; + +template <class R_> struct Point_weight { + CGAL_FUNCTOR_INIT_IGNORE(Point_weight) + typedef typename Get_type<R_, Weighted_point_tag>::type argument_type; + typedef typename Get_type<R_, FT_tag>::type result_type; + + result_type operator()(argument_type const&s)const{ + return s.weight(); + } +}; + +template <class R_> struct Power_distance : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Power_distance) + typedef typename Get_type<R_, Weighted_point_tag>::type first_argument_type; + typedef first_argument_type second_argument_type; + typedef typename Get_type<R_, FT_tag>::type result_type; + + result_type operator()(first_argument_type const&a, second_argument_type const&b)const{ + typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel()); + typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel()); + typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel()); + return sd(pdw(a),pdw(b))-pw(a)-pw(b); + } +}; +template <class R_> struct Power_distance_to_point : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Power_distance_to_point) + typedef typename Get_type<R_, Weighted_point_tag>::type first_argument_type; + typedef typename Get_type<R_, Point_tag>::type second_argument_type; + typedef typename Get_type<R_, FT_tag>::type result_type; + + result_type operator()(first_argument_type const&a, second_argument_type const&b)const{ + typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel()); + typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel()); + typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel()); + return sd(pdw(a),b)-pw(a); + } +}; + +template<class R_> struct Power_side_of_power_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Power_side_of_power_sphere) + typedef R_ R; + typedef typename Get_type<R, Oriented_side_tag>::type result_type; + + template<class Iter, class Pt> + result_type operator()(Iter const& f, Iter const& e, Pt const& p0) const { + typename Get_functor<R, Power_side_of_power_sphere_raw_tag>::type ptr(this->kernel()); + typename Get_functor<R, Point_drop_weight_tag>::type pdw(this->kernel()); + typename Get_functor<R, Point_weight_tag>::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<class R_> struct In_flat_power_side_of_power_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(In_flat_power_side_of_power_sphere) + typedef R_ R; + typedef typename Get_type<R, Oriented_side_tag>::type result_type; + + template<class Fo, class Iter, class Pt> + result_type operator()(Fo const& fo, Iter const& f, Iter const& e, Pt const& p0) const { + typename Get_functor<R, In_flat_power_side_of_power_sphere_raw_tag>::type ptr(this->kernel()); + typename Get_functor<R, Point_drop_weight_tag>::type pdw(this->kernel()); + typename Get_functor<R, Point_weight_tag>::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 <class R_> struct Power_center : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Power_center) + typedef typename Get_type<R_, Weighted_point_tag>::type WPoint; + typedef WPoint result_type; + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename Get_type<R_, FT_tag>::type FT; + template <class Iter> + 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<R_, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R_, Construct_ttag<Point_tag> >::type cp(this->kernel()); + typename Get_functor<R_, Point_dimension_tag>::type pd(this->kernel()); + typename Get_functor<R_, Squared_distance_to_origin_tag>::type sdo(this->kernel()); + typename Get_functor<R_, Power_distance_to_point_tag>::type pdp(this->kernel()); + typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel()); + typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel()); + typename Get_functor<R_, Construct_ttag<Weighted_point_tag> >::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<d;++j) { + m(i,j)=2*(c(p,j)-c(p0,j)); + b[i] = np - n0; + } + } + CGAL_assertion (i == d); + Vec res = typename CVec::Dimension()(d);; + //std::cout << "Mat: " << m << "\n Vec: " << one << std::endl; + LA::solve(res, CGAL_MOVE(m), CGAL_MOVE(b)); + //std::cout << "Sol: " << res << std::endl; + Point center = cp(d,LA::vector_begin(res),LA::vector_end(res)); + FT const& r2 = pdp (wp0, center); + return cwp(CGAL_MOVE(center), r2); + } +}; +} +CGAL_KD_DEFAULT_TYPE(Weighted_point_tag,(CGAL::KerD::Weighted_point<K>),(Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Weighted_point_tag>,(CartesianDKernelFunctors::Construct_weighted_point<K>),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_drop_weight_tag,(CartesianDKernelFunctors::Point_drop_weight<K>),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Point_weight_tag,(CartesianDKernelFunctors::Point_weight<K>),(Weighted_point_tag,Point_tag),()); +CGAL_KD_DEFAULT_FUNCTOR(Power_side_of_power_sphere_tag,(CartesianDKernelFunctors::Power_side_of_power_sphere<K>),(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<K>),(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<K>),(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<K>),(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<K>),(Weighted_point_tag,Point_tag),(Compute_point_cartesian_coordinate_tag,Construct_ttag<Point_tag>,Construct_ttag<Weighted_point_tag>,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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/array.h new file mode 100644 index 00000000..0ad9bb36 --- /dev/null +++ b/src/common/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 <boost/type_traits/is_arithmetic.hpp> +#include <boost/utility/enable_if.hpp> +#include <CGAL/Dimension.h> +#include <CGAL/NewKernel_d/utils.h> +#include <CGAL/array.h> +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/repetition/enum.hpp> + +#include <CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h> +#include <CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h> +#include <CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h> +#include <CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h> +#include <CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h> + + + +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<class NT_,class Dim_,class Max_dim_=Dim_> 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<class> struct Property : boost::false_type {}; + + static const unsigned d_=Max_dim_::value; + CGAL_static_assertion(d_ != (unsigned)UNKNOWN_DIMENSION); + + typedef cpp0x::array<NT,d_> 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<typename Iter> + 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<typename Iter> + 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<typename Iter,typename T> + 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<class...U> + Vector operator()(U&&...u) const { + static_assert(sizeof...(U)<=d_,"too many arguments"); + Vector a={{forward_safe<NT,U>(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<class H,class...U> + Vector operator()(H const& h,U&&...u) const { + static_assert(sizeof...(U)<=d_,"too many arguments"); + Vector a={{Rational_traits<NT>().make_rational(std::forward<U>(u),h)...}}; + return a; + } +#else + +#define CGAL_VAR(Z,N,_) Rational_traits<NT>().make_rational( t##N , h) +#define CGAL_CODE(Z,N,_) template <class H> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/avx4.h new file mode 100644 index 00000000..954a3c1b --- /dev/null +++ b/src/common/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 <x86intrin.h> + +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> +#include <CGAL/enum.h> // CGAL::Sign +#include <CGAL/number_utils.h> // 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<class,bool=true> struct Property : boost::false_type {}; + template<bool b> struct Property<Has_vector_plus_minus_tag,b> + : boost::true_type {}; + /* MAYBE? + template<bool b> struct Property<Has_vector_scalar_ops_tag,b> + : boost::true_type {}; + */ + template<bool b> struct Property<Has_determinant_of_vectors_tag,b> + : boost::true_type {}; + template<bool b> struct Property<Has_dot_product_tag,b> + : boost::true_type {}; + template<bool b> struct Property<Has_determinant_of_vectors_omit_last_tag,b> + : 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<typename Iter> + 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<typename Iter,typename T> + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_iterator_to_vectors.h b/src/common/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/src/common/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 <functional> +#include <CGAL/transforming_iterator.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> + +namespace CGAL { + +template <class LA, class Dim_=typename LA::Dimension, + class Max_dim_=typename LA::Max_dimension, + bool = LA::template Property<Has_determinant_of_iterator_to_points_tag>::value, + bool = LA::template Property<Has_determinant_of_iterator_to_vectors_tag>::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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_iterator_to_vectors<LA2> Other; + }; +}; + +template <class LA, class Dim_,class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_iterator_to_vectors +<LA, Dim_, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_iterator_to_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + // TODO: use std::minus, boost::bind, etc + template<class T> struct Minus_fixed { + T const& a; + Minus_fixed(T const&a_):a(a_){} + T operator()(T const&b)const{return b-a;} + }; + template<class Iter> + static NT determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Minus_fixed<Vector> f(a); + return LA::determinant_of_iterator_to_vectors(make_transforming_iterator(first,f),make_transforming_iterator(end,f)); + } + template<class Iter> + static Sign sign_of_determinant_of_iterator_to_points(Iter const&first, Iter const&end){ + Vector const&a=*first; ++first; + Minus_fixed<Vector> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_points_from_points.h b/src/common/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/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> + +namespace CGAL { + +template <class LA, class Dim_=typename LA::Dimension, + class Max_dim_=typename LA::Max_dimension, + bool = LA::template Property<Has_determinant_of_iterator_to_points_tag>::value, + bool = LA::template Property<Has_determinant_of_points_tag>::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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_points +<LA, Dimension_tag<2>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_points +<LA, Dimension_tag<3>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_points +<LA, Dimension_tag<4>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_points +<LA, Dimension_tag<5>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_points_from_points +<LA, Dimension_tag<6>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_points_from_points<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_points_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_iterator_to_vectors_from_vectors.h b/src/common/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/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> + +namespace CGAL { + +template <class LA, class Dim_=typename LA::Dimension, + class Max_dim_=typename LA::Max_dimension, + bool = LA::template Property<Has_determinant_of_iterator_to_vectors_tag>::value, + bool = LA::template Property<Has_determinant_of_vectors_tag>::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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_vectors_from_vectors +<LA, Dimension_tag<2>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_vectors_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_vectors_from_vectors +<LA, Dimension_tag<3>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_vectors_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_vectors_from_vectors +<LA, Dimension_tag<4>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_vectors_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_vectors_from_vectors +<LA, Dimension_tag<5>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_vectors_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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 <class LA, class Max_dim_> +struct Add_determinant_of_iterator_to_vectors_from_vectors +<LA, Dimension_tag<6>, 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<D2,D3> LA2; + typedef Add_determinant_of_iterator_to_vectors_from_vectors<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_iterator_to_vectors_tag, D> : + boost::true_type {}; + + template<class Iter> + 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<class Iter> + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_points_from_vectors.h new file mode 100644 index 00000000..7ddb73c3 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> + +namespace CGAL { + +template <class LA, class Dim_=typename LA::Dimension, + class Max_dim_=typename LA::Max_dimension, + bool = LA::template Property<Has_determinant_of_points_tag>::value, + bool = LA::template Property<Has_determinant_of_vectors_tag>::value + && LA::template Property<Has_vector_plus_minus_tag>::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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; +}; + +//FIXME: Use variadics and boost so it works in any dimension. +template <class LA, class Max_dim_> +struct Add_determinant_of_points_from_vectors_and_minus +<LA, Dimension_tag<2>, 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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_points_tag, D> : + 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 <class LA, class Max_dim_> +struct Add_determinant_of_points_from_vectors_and_minus +<LA, Dimension_tag<3>, 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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_points_tag, D> : + 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 <class LA, class Max_dim_> +struct Add_determinant_of_points_from_vectors_and_minus +<LA, Dimension_tag<4>, 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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_points_tag, D> : + 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 <class LA, class Max_dim_> +struct Add_determinant_of_points_from_vectors_and_minus +<LA, Dimension_tag<5>, 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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_points_tag, D> : + 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 <class LA, class Max_dim_> +struct Add_determinant_of_points_from_vectors_and_minus +<LA, Dimension_tag<6>, 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<D2,D3> LA2; + typedef Add_determinant_of_points_from_vectors_and_minus<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<Has_determinant_of_points_tag, D> : + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim.h new file mode 100644 index 00000000..64eafe69 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> +#include <CGAL/determinant_of_vectors.h> + +#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 <CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h> + +#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 <CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h> + +#undef CGAL_CLASS +#undef CGAL_TAG +#undef CGAL_FUNC +#undef CGAL_SIGN_FUNC +#undef CGAL_SHIFT + +#undef CGAL_ALLOWED_INCLUSION + +#endif diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/determinant_of_vectors_small_dim_internal.h new file mode 100644 index 00000000..b4856742 --- /dev/null +++ b/src/common/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 <class LA, class Dim_=typename LA::Dimension, + class Max_dim_=typename LA::Max_dimension, + bool=LA::template Property<CGAL_TAG>::value> +struct CGAL_CLASS : LA { + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef typename LA::template Rebind_dimension<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; +}; + +template <class LA, class Max_dim_> +struct CGAL_CLASS +<LA, Dimension_tag<2+CGAL_SHIFT>, 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<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<CGAL_TAG, D> : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b){ + return CGAL::determinant_of_vectors<NT>(a,b); + } + template <class V1, class V2> + static Sign CGAL_SIGN_FUNC(V1 const&a, V2 const&b){ + return CGAL::sign_of_determinant_of_vectors<NT>(a,b); + } +}; + +template <class LA, class Max_dim_> +struct CGAL_CLASS +<LA, Dimension_tag<3+CGAL_SHIFT>, 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<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<CGAL_TAG, D> : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c){ + return CGAL::determinant_of_vectors<NT>(a,b,c); + } + static Sign CGAL_SIGN_FUNC(Vector const&a, Vector const&b, + Vector const&c){ + return CGAL::sign_of_determinant_of_vectors<NT>(a,b,c); + } +}; + +template <class LA, class Max_dim_> +struct CGAL_CLASS +<LA, Dimension_tag<4+CGAL_SHIFT>, 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<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<CGAL_TAG, D> : + boost::true_type {}; + + static NT CGAL_FUNC(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return CGAL::determinant_of_vectors<NT>(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<NT>(a,b,c,d); + } +}; + +template <class LA, class Max_dim_> +struct CGAL_CLASS +<LA, Dimension_tag<5+CGAL_SHIFT>, 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<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<CGAL_TAG, D> : + 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<NT>(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<NT>(a,b,c,d,e); + } +}; + +template <class LA, class Max_dim_> +struct CGAL_CLASS +<LA, Dimension_tag<6+CGAL_SHIFT>, 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<D2,D3> LA2; + typedef CGAL_CLASS<LA2> Other; + }; + template<class P,class=void> struct Property : LA::template Property<P> {}; + template<class D> struct Property<CGAL_TAG, D> : + 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<NT>(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<NT>(a,b,c,d,e,f); + } +}; + +} diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/mix.h new file mode 100644 index 00000000..d4cfeeb1 --- /dev/null +++ b/src/common/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 <CGAL/Dimension.h> +namespace CGAL { + +template <class Static_, class Dynamic_, class NT_ ,class Dim_, class Max_dim_ = Dim_> +struct Mix_vector +: Dynamic_::template Rebind_dimension<Dim_, Max_dim_>::Other +{ + template <class D2, class D3 = D2> + struct Rebind_dimension { + typedef Mix_vector<Static_, Dynamic_, NT_, D2, D3> Other; + }; +}; + +template <class Static_, class Dynamic_, class NT_, int d, class Max_dim_> +struct Mix_vector<Static_, Dynamic_, NT_, Dimension_tag<d>, Max_dim_> +: Static_::template Rebind_dimension<Dimension_tag<d>, Max_dim_>::Other +{ + template <class D2, class D3 = D2> + struct Rebind_dimension { + typedef Mix_vector<Static_, Dynamic_, NT_, D2, D3> Other; + }; +}; +} +#endif + diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/sse2.h new file mode 100644 index 00000000..2a75385c --- /dev/null +++ b/src/common/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 <x86intrin.h> // FIXME: other platforms call it differently + +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/Dimension.h> +#include <CGAL/enum.h> // CGAL::Sign +#include <CGAL/number_utils.h> // 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<class,bool=true> struct Property : boost::false_type {}; + template<bool b> struct Property<Has_vector_plus_minus_tag,b> + : boost::true_type {}; + /* MAYBE? + template<bool b> struct Property<Has_vector_scalar_ops_tag,b> + : boost::true_type {}; + */ + template<bool b> struct Property<Has_determinant_of_vectors_tag,b> + : boost::true_type {}; + template<bool b> struct Property<Has_dot_product_tag,b> + : 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<typename Iter> + 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<typename Iter,typename T> + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/v2int.h new file mode 100644 index 00000000..b85a3734 --- /dev/null +++ b/src/common/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 <stdint.h> +#include <cmath> +#include <CGAL/array.h> +#include <CGAL/Dimension.h> +#include <CGAL/enum.h> +#include <CGAL/number_utils.h> +#include <CGAL/NT_converter.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/determinant_of_vectors.h> +#include <CGAL/NewKernel_d/functor_tags.h> + + +// 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<class Prop=Vector_2_int_prop1> + 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<class,bool=true> struct Property : boost::false_type {}; + //template<bool b> struct Property<Has_vector_plus_minus_tag,b> + // : boost::true_type {}; + template<bool b> struct Property<Has_determinant_of_vectors_tag,b> + : boost::true_type {}; + //template<bool b> struct Property<Has_determinant_of_points_tag,b> + // : boost::true_type {}; + // Advertise somehow that the sign_of_determinant* are exact? + + typedef cpp0x::array<NT1,2> 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<typename Iter> + 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<typename Iter,typename T> + 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<NT_converter<NT1,NT>,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<NT2>(a,b); + } + static CGAL::Sign sign_of_determinant_of_vectors(Vector a, Vector b) { + return CGAL::sign_of_determinant_of_vectors<NT2>(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<NT>(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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Vector/vector.h new file mode 100644 index 00000000..f9cc4e3c --- /dev/null +++ b/src/common/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 <boost/type_traits/is_arithmetic.hpp> +#include <boost/utility/enable_if.hpp> +#include <CGAL/Dimension.h> +#include <CGAL/NewKernel_d/utils.h> +#include <vector> +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/repetition/enum.hpp> +namespace CGAL { + +//Derive from a class that doesn't depend on Dim, or still use Dim for checking? +template<class NT_,class Dim_,class Max_dim_=Dim_> struct Vector_vector { + typedef NT_ NT; + typedef Dim_ Dimension; + typedef Max_dim_ Max_dimension; + typedef std::vector<NT> Vector; + template< class D2, class D3=D2 > + struct Rebind_dimension { + typedef Vector_vector< NT, D2, D3 > Other; + }; + template<class> struct Property : boost::false_type {}; + + struct Construct_vector { + struct Dimension { + Vector operator()(int d) const { + return Vector(d); + } + }; + + struct Iterator { + template<typename Iter> + 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<typename Iter> + 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<typename Iter,typename T> + 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<typename Iter,typename T> + 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<class...U> + Vector operator()(U&&...u) const { + //TODO: check the right number of {}, g++ accepts one and two + Vector a={forward_safe<NT,U>(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<class H,class...U> + 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<NT>().make_rational(x,y) ? + Vector a={Rational_traits<NT>().make_rational(std::forward<U>(u),h)...}; + return a; + } +#else + +#define CGAL_VAR(Z,N,_) a.push_back(Rational_traits<NT>().make_rational( t##N ,h)); +#define CGAL_CODE(Z,N,_) template<class H> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h new file mode 100644 index 00000000..44e9aa96 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/is_iterator.h> + +#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 <CGAL/NewKernel_d/Wrapper/Point_d.h> +#include <CGAL/NewKernel_d/Wrapper/Vector_d.h> +#include <CGAL/NewKernel_d/Wrapper/Segment_d.h> +#include <CGAL/NewKernel_d/Wrapper/Sphere_d.h> +#include <CGAL/NewKernel_d/Wrapper/Hyperplane_d.h> +#include <CGAL/NewKernel_d/Wrapper/Weighted_point_d.h> + +#include <CGAL/NewKernel_d/Wrapper/Ref_count_obj.h> + +#include <boost/mpl/or.hpp> +#include <boost/mpl/contains.hpp> +#include <boost/mpl/vector.hpp> + +//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<class T,bool=has_Is_wrapper<T>::value> struct Is_wrapper { + enum { value=false }; + typedef Tag_false type; +}; +template<class T> struct Is_wrapper<T,true> { + typedef typename T::Is_wrapper type; + enum { value=type::value }; +}; + +template<class T,bool=is_iterator_type<T,std::input_iterator_tag>::value> struct Is_wrapper_iterator { + enum { value=false }; + typedef Tag_false type; +}; +template<class T> struct Is_wrapper_iterator<T,true> : + Is_wrapper<typename std::iterator_traits<typename CGAL::decay<T>::type>::value_type> +{ }; + +struct Forward_rep { +//TODO: make a good C++0X version with perfect forwarding +//#ifdef CGAL_CXX11 +//template <class T,class=typename std::enable_if<!Is_wrapper<typename std::decay<T>::type>::value&&!Is_wrapper_iterator<typename std::decay<T>::type>::value>::type> +//T&& operator()(typename std::remove_reference<T>::type&& t) const {return static_cast<T&&>(t);}; +//template <class T,class=typename std::enable_if<!Is_wrapper<typename std::decay<T>::type>::value&&!Is_wrapper_iterator<typename std::decay<T>::type>::value>::type> +//T&& operator()(typename std::remove_reference<T>::type& t) const {return static_cast<T&&>(t);}; +// +//template <class T,class=typename std::enable_if<Is_wrapper<typename std::decay<T>::type>::value>::type> +//typename Type_copy_cvref<T,typename std::decay<T>::type::Rep>::type&& +//operator()(T&& t) const { +// return static_cast<typename Type_copy_cvref<T,typename std::decay<T>::type::Rep>::type&&>(t.rep()); +//}; +// +//template <class T,class=typename std::enable_if<Is_wrapper_iterator<typename std::decay<T>::type>::value>::type> +//transforming_iterator<Forward_rep,typename std::decay<T>::type> +//operator()(T&& t) const { +// return make_transforming_iterator(std::forward<T>(t),Forward_rep()); +//}; +//#else +template <class T,bool=Is_wrapper<T>::value,bool=Is_wrapper_iterator<T>::value> struct result_; +template <class T> struct result_<T,false,false>{typedef T const& type;}; +template <class T> struct result_<T,true,false>{typedef typename decay<T>::type::Rep const& type;}; +template <class T> struct result_<T,false,true>{typedef transforming_iterator<Forward_rep,typename decay<T>::type> type;}; +template<class> struct result; +template<class T> struct result<Forward_rep(T)> : result_<T> {}; + +template <class T> typename boost::disable_if<boost::mpl::or_<Is_wrapper<T>,Is_wrapper_iterator<T> >,T>::type const& operator()(T const& t) const {return t;} +template <class T> typename boost::disable_if<boost::mpl::or_<Is_wrapper<T>,Is_wrapper_iterator<T> >,T>::type& operator()(T& t) const {return t;} + +template <class T> typename T::Rep const& operator()(T const& t, typename boost::enable_if<Is_wrapper<T> >::type* = 0) const {return t.rep();} + +template <class T> transforming_iterator<Forward_rep,typename boost::enable_if<Is_wrapper_iterator<T>,T>::type> operator()(T const& t) const {return make_transforming_iterator(t,Forward_rep());} +//#endif +}; +} + +template <class B, class K, class T, bool = Provides_type<B, T>::value> +struct Map_wrapping_type : Get_type<B, T> {}; +#define CGAL_REGISTER_OBJECT_WRAPPER(X) \ + template <class B, class K> \ + struct Map_wrapping_type <B, K, X##_tag, true> { \ + typedef Wrap::X##_d<K> 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<Derived_, Self>::type Derived; + // FIXME: The list doesn't belong here. + typedef boost::mpl::vector<Point_tag,Segment_tag,Sphere_tag,Vector_tag,Hyperplane_tag> Wrapped_list; + + template <class T> + struct Type : Map_wrapping_type<Base_, Derived, T> {}; + + //Translate the arguments + template <class T, class D = void, + class=typename Get_functor_category<Derived,T>::type, + bool=Provides_functor<Kernel_base, T>::value, + bool=boost::mpl::contains<Wrapped_list,typename map_result_tag<T>::type>::type::value> + struct Functor { + typedef typename Get_functor<Kernel_base, T>::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename B::result_type result_type; +#ifdef CGAL_CXX11 + template<class...U> 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<BOOST_PP_ENUM_PARAMS(N,class U)> 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<BOOST_PP_ENUM_PARAMS(N,class U),class V> 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 <class T, class D, class C, bool b> + struct Functor <T, D, C, false, b> + : Get_functor <Kernel_base, T> {}; + + //Translate both the arguments and the result + //TODO: Check Is_wrapper instead of relying on map_result_tag? + template<class T,class D> struct Functor<T,D,Construct_tag,true,true> { + typedef typename Get_functor<Kernel_base, T>::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename map_result_tag<T>::type result_tag; + // FIXME: Self or Derived? + typedef typename Get_type<Self,result_tag>::type result_type; +#ifdef CGAL_CXX11 + template<class...U> 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<BOOST_PP_ENUM_PARAMS(N,class U)> 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 <class T, class=void> struct Type : Get_type<Base_, T> {}; +#define CGAL_Kernel_obj(X,Y) \ + template <class D> struct Type<X##_tag, D> { typedef Ref_count_obj<Cartesian_refcount, X##_tag> type; }; + + CGAL_Kernel_obj(Point,point) + CGAL_Kernel_obj(Vector,vector) +#undef CGAL_Kernel_obj + + template<class T> struct Dispatch { + //typedef typename map_functor_type<T>::type f_t; + typedef typename map_result_tag<T>::type r_t; + enum { + is_nul = boost::is_same<typename Get_functor<Kernel_base, T>::type,Null_functor>::value, + ret_rcobj = boost::is_same<r_t,Point_tag>::value || boost::is_same<r_t,Vector_tag>::value + }; + }; + + //Translate the arguments + template<class T,class D=void,bool=Dispatch<T>::is_nul,bool=Dispatch<T>::ret_rcobj> struct Functor { + typedef typename Get_functor<Kernel_base, T>::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename B::result_type result_type; +#ifdef CGAL_CXX11 + template<class...U> 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<BOOST_PP_ENUM_PARAMS(N,class U)> 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<class T,class D,bool b> struct Functor<T,D,true,b> { + typedef Null_functor type; + }; + + template<class T,class D> struct Functor<T,D,false,true> { + typedef typename Get_functor<Kernel_base, T>::type B; + struct type { + B b; + type(){} + type(Self const&k):b(k){} + typedef typename map_result_tag<T>::type result_tag; + typedef typename Get_type<Self,result_tag>::type result_type; +#ifdef CGAL_CXX11 + template<class...U> 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<BOOST_PP_ENUM_PARAMS(N,class U)> 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Hyperplane_d.h new file mode 100644 index 00000000..54fd50bd --- /dev/null +++ b/src/common/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 <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Hyperplane_d : public Get_type<typename R_::Kernel_base, Hyperplane_tag>::type +{ + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Vector_tag>::type Vector_; + typedef typename Get_functor<Kbase, Construct_ttag<Hyperplane_tag> >::type CHBase; + typedef typename Get_functor<Kbase, Orthogonal_vector_tag>::type OVBase; + typedef typename Get_functor<Kbase, Hyperplane_translation_tag>::type HTBase; + + typedef Hyperplane_d Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Hyperplane_tag>::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef typename Increment_dimension<Ambient_dimension,-1>::type Feature_dimension; + + typedef typename Get_type<Kbase, Hyperplane_tag>::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Hyperplane_d> >::value>::type> explicit Hyperplane_d(U&&...u) + : Rep(CHBase()(std::forward<U>(u)...)){} + +// // called from Construct_point_d +// template<class...U> explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Hyperplane_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Hyperplane_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CHBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Point_d.h new file mode 100644 index 00000000..0718c947 --- /dev/null +++ b/src/common/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 <ostream> +#include <CGAL/Origin.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Point_d : public Get_type<typename R_::Kernel_base, Point_tag>::type + // Deriving won't work if the point is just a __m256d. + // Test boost/std::is_class for instance +{ + typedef typename Get_type<R_, RT_tag>::type RT_; + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Vector_tag>::type Vector_; + typedef typename Get_functor<Kbase, Construct_ttag<Point_tag> >::type CPBase; + typedef typename Get_functor<Kbase, Compute_point_cartesian_coordinate_tag>::type CCBase; + typedef typename Get_functor<Kbase, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CPI; + + + typedef Point_d Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Point_tag>::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<Kbase, Point_tag>::type Rep; + //typedef typename CGAL::decay<typename boost::result_of<CPI(Rep,Begin_tag)>::type>::type Cartesian_const_iterator; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Point_d> >::value>::type> explicit Point_d(U&&...u) + : Rep(CPBase()(std::forward<U>(u)...)){} + +// // called from Construct_point_d +// template<class...U> explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Point_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Point_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CPBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<CCBase(Rep,int)>::type cartesian(int i)const{ + return CCBase()(rep(),i); + } + typename boost::result_of<CCBase(Rep,int)>::type operator[](int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of<CPI(Rep,Begin_tag)>::type cartesian_begin()const{ + return CPI()(rep(),Begin_tag()); + } + + typename boost::result_of<CPI(Rep,End_tag)>::type cartesian_end()const{ + return CPI()(rep(),End_tag()); + } + + int dimension() const { + typedef typename Get_functor<Kbase, Point_dimension_tag>::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<FT_,RT>::Type & c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + typename Qualified_result_of<typename R::Compute_x_3, Vector_3>::type + x() const + { + return R().compute_x_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_y_3, Vector_3>::type + y() const + { + return R().compute_y_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_z_3, Vector_3>::type + z() const + { + return R().compute_z_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hx_3, Vector_3>::type + hx() const + { + return R().compute_hx_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hy_3, Vector_3>::type + hy() const + { + return R().compute_hy_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hz_3, Vector_3>::type + hz() const + { + return R().compute_hz_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hw_3, Vector_3>::type + hw() const + { + return R().compute_hw_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_x_3, Vector_3>::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<typename R::Compute_hw_3, Vector_3>::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<typename R::Compute_squared_length_3, Vector_3>::type + squared_length() const + { + return R().compute_squared_length_3_object()(*this); + } +*/ +}; +#if 0 +template <class R_> Point_d<R_>::Point_d(Point_d &)=default; +#endif + +//TODO: IO + +template <class R_> +std::ostream& operator <<(std::ostream& os, const Point_d<R_>& p) +{ + typedef typename R_::Kernel_base Kbase; + typedef typename Get_functor<Kbase, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CPI; + // Should just be "auto"... + typename CGAL::decay<typename boost::result_of< + CPI(typename Point_d<R_>::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 <class R_> +//Vector_d<R_> operator+(const Vector_d<R_>& v,const Vector_d<R_>& w) const +//{ +// return typename R::template Construct<Sum_of_vectors_tag>::type()(v,w); +//} +// +//template <class R_> +//Vector_d<R_> operator-(const Vector_d<R_>& v,const Vector_d<R_>& w) const +//{ +// return typename R::template Construct<Difference_of_vectors_tag>::type()(v,w); +//} + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_POINT_D_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Ref_count_obj.h new file mode 100644 index 00000000..f33e14c0 --- /dev/null +++ b/src/common/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 <CGAL/Origin.h> +#include <CGAL/Handle_for.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +// no need for a fancy interface here, people can use the Point_d wrapper on +// top. + +namespace CGAL { + +template <class R_, class Tag_> +class Ref_count_obj +{ + typedef typename R_::Kernel_base Kbase; + typedef typename Get_functor<Kbase, Construct_ttag<Tag_> >::type CBase; + + typedef Ref_count_obj Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Tag_>::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<Kbase, Tag_>::type Rep; + typedef Handle_for<Rep> Data; + +private: + Data data; +public: + + const Rep& rep() const + { + return CGAL::get_pointee_or_identity(data); + } + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Ref_count_obj> >::value>::type> explicit Ref_count_obj(U&&...u) + : data(Eval_functor(),CBase(),std::forward<U>(u)...){} + + template<class F,class...U> explicit Ref_count_obj(Eval_functor&&,F&&f,U&&...u) + : data(Eval_functor(),std::forward<F>(f),std::forward<U>(u)...){} + + // try not to use these + Ref_count_obj(Rep const& v) : data(v) {} + Ref_count_obj(Rep& v) : data(static_cast<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Ref_count_obj(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : data(Eval_functor(),CBase(),BOOST_PP_ENUM_PARAMS(N,t)) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<class F> + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Segment_d.h new file mode 100644 index 00000000..bfb20a77 --- /dev/null +++ b/src/common/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 <CGAL/Origin.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Segment_d : public Get_type<typename R_::Kernel_base, Segment_tag>::type +{ + typedef typename Get_type<R_, RT_tag>::type RT_; + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef typename Get_functor<Kbase, Construct_ttag<Point_tag> >::type CPBase; + typedef typename Get_functor<Kbase, Construct_ttag<Segment_tag> >::type CSBase; + typedef typename Get_functor<Kbase, Segment_extremity_tag>::type CSEBase; + + typedef Segment_d Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Segment_tag>::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<Kbase, Segment_tag>::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Segment_d> >::value>::type> explicit Segment_d(U&&...u) + : Rep(CSBase()(std::forward<U>(u)...)){} + +// // called from Construct_point_d +// template<class...U> explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Segment_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Segment_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CSBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Sphere_d.h new file mode 100644 index 00000000..87f0c66e --- /dev/null +++ b/src/common/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 <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Sphere_d : public Get_type<typename R_::Kernel_base, Sphere_tag>::type +{ + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef typename Get_functor<Kbase, Construct_ttag<Sphere_tag> >::type CSBase; + typedef typename Get_functor<Kbase, Center_of_sphere_tag>::type COSBase; + typedef typename Get_functor<Kbase, Squared_radius_tag>::type SRBase; + + typedef Sphere_d Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Sphere_tag>::type>::value)); + +public: + + typedef Tag_true Is_wrapper; + typedef typename R_::Default_ambient_dimension Ambient_dimension; + typedef typename Increment_dimension<Ambient_dimension,-1>::type Feature_dimension; + + typedef typename Get_type<Kbase, Sphere_tag>::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Sphere_d> >::value>::type> explicit Sphere_d(U&&...u) + : Rep(CSBase()(std::forward<U>(u)...)){} + +// // called from Construct_point_d +// template<class...U> explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Sphere_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Sphere_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CSBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Vector_d.h new file mode 100644 index 00000000..b7d1f0d0 --- /dev/null +++ b/src/common/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 <CGAL/Origin.h> +#include <CGAL/Kernel/mpl.h> +#include <CGAL/representation_tags.h> +#include <CGAL/assertions.h> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Vector_d : public Get_type<typename R_::Kernel_base, Vector_tag>::type +{ + typedef typename Get_type<R_, RT_tag>::type RT_; + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef typename Get_functor<Kbase, Construct_ttag<Vector_tag> >::type CVBase; + typedef typename Get_functor<Kbase, Compute_vector_cartesian_coordinate_tag>::type CCBase; + typedef typename Get_functor<Kbase, Construct_ttag<Vector_cartesian_const_iterator_tag> >::type CVI; + typedef typename Get_functor<Kbase, Squared_length_tag>::type SLBase; + + typedef Vector_d Self; + CGAL_static_assertion((boost::is_same<Self, typename Get_type<R_, Vector_tag>::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<Kbase, Vector_tag>::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Vector_d> >::value>::type> explicit Vector_d(U&&...u) + : Rep(CVBase()(std::forward<U>(u)...)){} + +// // called from Construct_vector_d +// template<class...U> explicit Vector_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Vector_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Vector_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CVBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<CCBase(Rep,int)>::type cartesian(int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of<CCBase(Rep,int)>::type operator[](int i)const{ + return CCBase()(rep(),i); + } + + typename boost::result_of<CVI(Rep,Begin_tag)>::type cartesian_begin()const{ + return CVI()(rep(),Begin_tag()); + } + + typename boost::result_of<CVI(Rep,End_tag)>::type cartesian_end()const{ + return CVI()(rep(),End_tag()); + } + + Vector_d operator-() const + { + return typename Get_functor<R, Opposite_vector_tag>::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<FT_,RT>::Type & c) const + { + return R().construct_divided_vector_d_object()(*this,c); + } + + typename Qualified_result_of<typename R::Compute_x_3, Vector_3>::type + x() const + { + return R().compute_x_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_y_3, Vector_3>::type + y() const + { + return R().compute_y_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_z_3, Vector_3>::type + z() const + { + return R().compute_z_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hx_3, Vector_3>::type + hx() const + { + return R().compute_hx_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hy_3, Vector_3>::type + hy() const + { + return R().compute_hy_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hz_3, Vector_3>::type + hz() const + { + return R().compute_hz_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_hw_3, Vector_3>::type + hw() const + { + return R().compute_hw_3_object()(*this); + } + + typename Qualified_result_of<typename R::Compute_x_3, Vector_3>::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<typename R::Compute_hw_3, Vector_3>::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<SLBase(Rep)>::type squared_length()const{ + return SLBase()(rep()); + } +}; +#if 0 +template <class R_> Vector_d<R_>::Vector_d(Vector_d &)=default; +#endif + +//TODO: IO + +template <class R_> +Vector_d<R_> operator+(const Vector_d<R_>& v,const Vector_d<R_>& w) +{ + return typename Get_functor<R_, Sum_of_vectors_tag>::type()(v,w); +} + +template <class R_> +Vector_d<R_> operator-(const Vector_d<R_>& v,const Vector_d<R_>& w) +{ + return typename Get_functor<R_, Difference_of_vectors_tag>::type()(v,w); +} + +} //namespace Wrap +} //namespace CGAL + +#endif // CGAL_WRAPPER_VECTOR_D_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/Wrapper/Weighted_point_d.h new file mode 100644 index 00000000..877eea21 --- /dev/null +++ b/src/common/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 <CGAL/representation_tags.h> +#include <boost/static_assert.hpp> +#include <boost/type_traits.hpp> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/Dimension.h> +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#endif +#include <boost/utility/result_of.hpp> + +namespace CGAL { +namespace Wrap { + +template <class R_> +class Weighted_point_d : public Get_type<typename R_::Kernel_base, Weighted_point_tag>::type +{ + typedef typename Get_type<R_, FT_tag>::type FT_; + typedef typename R_::Kernel_base Kbase; + typedef typename Get_type<R_, Point_tag>::type Point_; + typedef typename Get_functor<Kbase, Construct_ttag<Weighted_point_tag> >::type CWPBase; + typedef typename Get_functor<Kbase, Point_drop_weight_tag>::type PDWBase; + typedef typename Get_functor<Kbase, Point_weight_tag>::type PWBase; + + typedef Weighted_point_d Self; + BOOST_STATIC_ASSERT((boost::is_same<Self, typename Get_type<R_, Weighted_point_tag>::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<Kbase, Weighted_point_tag>::type Rep; + + const Rep& rep() const + { + return *this; + } + + Rep& rep() + { + return *this; + } + + typedef R_ R; + +#ifdef CGAL_CXX11 + template<class...U,class=typename std::enable_if<!std::is_same<std::tuple<typename std::decay<U>::type...>,std::tuple<Weighted_point_d> >::value>::type> explicit Weighted_point_d(U&&...u) + : Rep(CWPBase()(std::forward<U>(u)...)){} + +// // called from Construct_point_d +// template<class...U> explicit Point_d(Eval_functor&&,U&&...u) +// : Rep(Eval_functor(), std::forward<U>(u)...){} + template<class F,class...U> explicit Weighted_point_d(Eval_functor&&,F&&f,U&&...u) + : Rep(std::forward<F>(f)(std::forward<U>(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<Rep const&>(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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + explicit Weighted_point_d(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const&t)) \ + : Rep(CWPBase()( \ + BOOST_PP_ENUM_PARAMS(N,t))) {} \ + \ + template<class F,BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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<BOOST_PP_ENUM_PARAMS(N,class T)> \ + 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/function_objects_cartesian.h new file mode 100644 index 00000000..5a132ad2 --- /dev/null +++ b/src/common/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 <CGAL/NewKernel_d/utils.h> +#include <CGAL/Dimension.h> +#include <CGAL/Uncertain.h> +#include <CGAL/NewKernel_d/store_kernel.h> +#include <CGAL/is_iterator.h> +#include <CGAL/iterator_from_indices.h> +#include <CGAL/number_utils.h> +#include <CGAL/Kernel/Return_base_tag.h> +#include <CGAL/transforming_iterator.h> +#include <CGAL/transforming_pair_iterator.h> +#include <CGAL/NewKernel_d/functor_tags.h> +#include <CGAL/NewKernel_d/functor_properties.h> +#include <CGAL/predicates/sign_of_determinant.h> +#include <functional> +#ifdef CGAL_CXX11 +#include <initializer_list> +#endif + +namespace CGAL { +namespace CartesianDKernelFunctors { +namespace internal { +template<class,int> struct Dimension_at_most { enum { value = false }; }; +template<int a,int b> struct Dimension_at_most<Dimension_tag<a>,b> { + enum { value = (a <= b) }; +}; +} + +template<class R_,class D_=typename R_::Default_ambient_dimension,bool=internal::Dimension_at_most<D_,6>::value> struct Orientation_of_points : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename R::LA::Square_matrix Matrix; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j){ + m(i,j)=c(p,j)-c(p0,j); + // should we cache the coordinates of p0 in case they are computed? + } + } + return R::LA::sign_of_determinant(CGAL_MOVE(m)); + } + +#ifdef CGAL_CXX11 + // Since the dimension is at least 2, there are at least 3 points and no ambiguity with iterators. + // template <class...U,class=typename std::enable_if<std::is_same<Dimension_tag<sizeof...(U)-1>,typename R::Default_ambient_dimension>::value>::type> + template <class...U,class=typename std::enable_if<(sizeof...(U)>=3)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward<U>(u)...}); + } + + template <class P> + result_type operator()(std::initializer_list<P> 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<R, Compute_point_cartesian_coordinate_tag>::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<class R_,int d> struct Orientation_of_points<R_,Dimension_tag<d>,true> : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + template<class>struct Help; + template<int...I>struct Help<Indices<I...> > { + template<class C,class P,class T> result_type operator()(C const&c,P const&x,T&&t)const{ + return sign_of_determinant<RT>(c(std::get<I/d>(t),I%d)-c(x,I%d)...); + } + }; + template<class P0,class...P> result_type operator()(P0 const&x,P&&...p)const{ + static_assert(d==sizeof...(P),"Wrong number of arguments"); + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + return Help<typename N_increasing_indices<d*d>::type>()(c,x,std::forward_as_tuple(std::forward<P>(p)...)); + } + + + template<int N,class Iter,class...U> result_type help2(Dimension_tag<N>, Iter f, Iter const&e, U&&...u)const{ + auto const&p=*f; + return help2(Dimension_tag<N-1>(),++f,e,std::forward<U>(u)...,p); + } + template<class Iter,class...U> 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>(u)...); + } + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + return help2(Dimension_tag<d+1>(),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<class R_> struct Orientation_of_points<R_,Dimension_tag<N>,true> : private Store_kernel<R_> { \ + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) \ + typedef R_ R; \ + typedef typename Get_type<R, RT_tag>::type RT; \ + typedef typename Get_type<R, Point_tag>::type Point; \ + typedef typename Get_type<R, Orientation_tag>::type result_type; \ + result_type operator()(Point const&x, BOOST_PP_ENUM_PARAMS(N,Point const&p)) const { \ + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); \ + BOOST_PP_REPEAT(N,CGAL_VAR4,) \ + return sign_of_determinant<RT>(BOOST_PP_ENUM(N,CGAL_VAR2,N)); \ + } \ + template<class Iter> \ + 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<class R_> struct Orientation_of_points<R_,Dimension_tag<1>,true> : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_points) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + result_type operator()(Point const&x, Point const&y) const { + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + // No sign_of_determinant(RT) :-( + return CGAL::compare(c(y,0),c(x,0)); + } + template<class Iter> + 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<K>),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Orientation_of_vectors : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation_of_vectors) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename R::LA::Square_matrix Matrix; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Compute_vector_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j){ + m(0,j)=c(v0,j); + } + for(int i=1;++f!=e;++i) { + Vector const& v=*f; + for(int j=0;j<d;++j){ + m(i,j)=c(v,j); + } + } + return R::LA::sign_of_determinant(CGAL_MOVE(m)); + } + +#ifdef CGAL_CXX11 + template <class...U,class=typename std::enable_if<(sizeof...(U)>=3)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward<U>(u)...}); + } + + template <class V> + result_type operator()(std::initializer_list<V> l) const { + return operator()(l.begin(),l.end()); + } +#else + //TODO +#endif +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Orientation_of_vectors_tag,(CartesianDKernelFunctors::Orientation_of_vectors<K>),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Linear_rank : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Linear_rank) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + // Computing a sensible Uncertain<int> is not worth it + typedef int result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Compute_vector_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j){ + m(j,0)=c(v0,j); + } + for(int i=1; ++f!=e; ++i){ + Vector const& v = *f; + for(int j=0;j<d;++j){ + m(j,i)=c(v,j); + } + } + return R::LA::rank(CGAL_MOVE(m)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Linear_rank_tag,(CartesianDKernelFunctors::Linear_rank<K>),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Linearly_independent : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Linearly_independent) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Point_dimension_tag>::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<R, Linear_rank_tag>::type lr(this->kernel()); + return lr(f,e) == n; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Linearly_independent_tag,(CartesianDKernelFunctors::Linearly_independent<K>),(Vector_tag),(Point_dimension_tag,Linear_rank_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Contained_in_linear_hull : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Contained_in_linear_hull) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + // Computing a sensible Uncertain<bool> is not worth it + typedef bool result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template<class Iter,class V> + result_type operator()(Iter f, Iter e,V const&w)const{ + typename Get_functor<R, Compute_vector_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j){ + m(j,i)=c(v,j); + } + } + for(int j=0;j<d;++j){ + m(j,n)=c(w,j); + } + int r1 = R::LA::rank(m); + // FIXME: Don't use eigen directly, go through an interface in LA... + m.conservativeResize(Eigen::NoChange, n); + int r2 = R::LA::rank(CGAL_MOVE(m)); + return r1 == r2; + // TODO: This is very very far from optimal... + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Contained_in_linear_hull_tag,(CartesianDKernelFunctors::Contained_in_linear_hull<K>),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Affine_rank : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Affine_rank) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type Point; + // Computing a sensible Uncertain<int> is not worth it + typedef int result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j){ + m(j,i)=c(p,j)-c(p0,j); + // TODO: cache p0[j] in case it is computed? + } + } + return R::LA::rank(CGAL_MOVE(m)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Affine_rank_tag,(CartesianDKernelFunctors::Affine_rank<K>),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Affinely_independent : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Affinely_independent) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + + template<class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + std::ptrdiff_t n=std::distance(f,e); + int d=pd(*f); + if (--n>d) return false; + typename Get_functor<R, Affine_rank_tag>::type ar(this->kernel()); + return ar(f,e) == n; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Affinely_independent_tag,(CartesianDKernelFunctors::Affinely_independent<K>),(Point_tag),(Point_dimension_tag,Affine_rank_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Contained_in_simplex : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Contained_in_simplex) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type Point; + // Computing a sensible Uncertain<*> is not worth it + // typedef typename Get_type<R, Boolean_tag>::type result_type; + typedef bool result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Dynamic_matrix Matrix; + typedef typename LA::Dynamic_vector DynVec; + typedef typename LA::Vector Vec; + + template<class Iter, class P> + result_type operator()(Iter f, Iter e, P const&q)const{ + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::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<d;++j) b[j]=c(q,j); + b[d]=1; + + for(int i=0; f!=e; ++i,++f){ + Point const& p = *f; + for(int j=0;j<d;++j){ + m(j,i)=c(p,j); + } + m(d,i)=1; + } + // If the simplex has full dimension, there must be a solution, only the signs need to be checked. + if (n == d+1) + LA::solve(a,CGAL_MOVE(m),CGAL_MOVE(b)); + else if (!LA::solve_and_check(a,CGAL_MOVE(m),CGAL_MOVE(b))) + return false; + for(int i=0;i<n;++i){ + if (a[i]<0) return false; + } + return true; + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Contained_in_simplex_tag,(CartesianDKernelFunctors::Contained_in_simplex<K>),(Point_tag),(Point_dimension_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { + namespace internal { + template<class Ref_> + struct Matrix_col_access { + typedef Ref_ result_type; + int col; + Matrix_col_access(int r):col(r){} + template<class Mat> Ref_ operator()(Mat const& m, std::ptrdiff_t row)const{ + return m(row,col); + } + }; + } +template<class R_> struct Linear_base : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Linear_base) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, FT_tag>::type FT; + typedef void result_type; + typedef typename R::LA::Dynamic_matrix Matrix; + + template<class Iter, class Oter> + result_type operator()(Iter f, Iter e, Oter&o)const{ + typename Get_functor<R, Compute_vector_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type vd(this->kernel()); + typename Get_functor<R, Construct_ttag<Vector_tag> >::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<d;++j){ + m(0,j)=c(v0,j); + } + for(int i=1; ++f!=e; ++i){ + Vector const& v = *f; + for(int j=0;j<d;++j){ + m(i,j)=c(v,j); + } + } + Matrix b = R::LA::basis(CGAL_MOVE(m)); + for(int i=0; i < R::LA::columns(b); ++i){ + //*o++ = Vector(b.col(i)); + typedef +#ifdef CGAL_CXX11 + decltype(std::declval<const Matrix>()(0,0)) +#else + FT +#endif + Ref; + typedef Iterator_from_indices<Matrix, FT, Ref, + internal::Matrix_col_access<Ref> > IFI; + *o++ = cv(IFI(b,0,i),IFI(b,d,i)); + } + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Linear_base_tag,(CartesianDKernelFunctors::Linear_base<K>),(Vector_tag),(Point_dimension_tag,Compute_vector_cartesian_coordinate_tag)); + +#if 0 +namespace CartesianDKernelFunctors { +template<class R_,bool=boost::is_same<typename R_::Point,typename R_::Vector>::value> struct Orientation : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename Get_functor<R, Orientation_of_points_tag>::type OP; + typedef typename Get_functor<R, Orientation_of_vectors_tag>::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<class Iter> + result_type operator()(Iter const&f, Iter const& e)const{ + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + typename std::iterator_traits<Iter>::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<class R_> struct Orientation<R_,false> : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Orientation) + typedef R_ R; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Orientation_tag>::type result_type; + typedef typename Get_functor<R, Orientation_of_points_tag>::type OP; + typedef typename Get_functor<R, Orientation_of_vectors_tag>::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<class Iter> + typename boost::enable_if<is_iterator_to<Iter,Point>,result_type>::type + operator()(Iter const&f, Iter const& e)const{ + return OP(this->kernel())(f,e); + } + template<class Iter> + typename boost::enable_if<is_iterator_to<Iter,Vector>,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<class R_> struct Power_side_of_power_sphere_raw : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Power_side_of_power_sphere_raw) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Oriented_side_tag>::type result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Square_matrix Matrix; + + template<class IterP, class IterW, class Pt, class Wt> + result_type operator()(IterP f, IterP const& e, IterW fw, Pt const& p0, Wt const& w0) const { + typedef typename Get_functor<R, Squared_distance_to_origin_tag>::type Sqdo; + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + + int d=pd(p0); + Matrix m(d+1,d+1); + if(CGAL::Is_stored<Sqdo>::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<d;++j){ + RT const& x=c(p,j); + m(i,j)=x-c(p0,j); + } + m(i,d) = sqdo(p) - *fw - h0; + } + } else { + for(int i=0;f!=e;++f,++fw,++i) { + Point const& p=*f; + m(i,d) = w0 - *fw; + for(int j=0;j<d;++j){ + RT const& x=c(p,j); + m(i,j)=x-c(p0,j); + m(i,d)+=CGAL::square(m(i,j)); + } + } + } + if(d%2) + return -LA::sign_of_determinant(CGAL_MOVE(m)); + else + return LA::sign_of_determinant(CGAL_MOVE(m)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Power_side_of_power_sphere_raw_tag,(CartesianDKernelFunctors::Power_side_of_power_sphere_raw<K>),(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<class R_> struct Side_of_oriented_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Side_of_oriented_sphere) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Oriented_side_tag>::type result_type; + typedef typename Increment_dimension<typename R::Default_ambient_dimension>::type D1; + typedef typename Increment_dimension<typename R::Max_ambient_dimension>::type D2; + typedef typename R::LA::template Rebind_dimension<D1,D2>::Other LA; + typedef typename LA::Square_matrix Matrix; + + template<class Iter> + result_type operator()(Iter f, Iter const& e)const{ + Point const& p0=*f++; // *--e ? + return this->operator()(f,e,p0); + } + + template<class Iter> + result_type operator()(Iter f, Iter const& e, Point const& p0) const { + typedef typename Get_functor<R, Squared_distance_to_origin_tag>::type Sqdo; + typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R, Point_dimension_tag>::type pd(this->kernel()); + + int d=pd(p0); + Matrix m(d+1,d+1); + if(CGAL::Is_stored<Sqdo>::value) { + Sqdo sqdo(this->kernel()); + for(int i=0;f!=e;++f,++i) { + Point const& p=*f; + for(int j=0;j<d;++j){ + RT const& x=c(p,j); + m(i,j)=x-c(p0,j); + } + m(i,d) = sqdo(p) - sqdo(p0); + } + } else { + for(int i=0;f!=e;++f,++i) { + Point const& p=*f; + m(i,d) = 0; + for(int j=0;j<d;++j){ + RT const& x=c(p,j); + m(i,j)=x-c(p0,j); + m(i,d)+=CGAL::square(m(i,j)); + } + } + } + if(d%2) + return -LA::sign_of_determinant(CGAL_MOVE(m)); + else + return LA::sign_of_determinant(CGAL_MOVE(m)); + } + +#ifdef CGAL_CXX11 + template <class...U,class=typename std::enable_if<(sizeof...(U)>=4)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward<U>(u)...}); + } + + template <class P> + result_type operator()(std::initializer_list<P> 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<K>),(Point_tag),(Point_dimension_tag,Squared_distance_to_origin_tag,Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template <class R_> struct Construct_circumcenter : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Construct_circumcenter) + typedef typename Get_type<R_, Point_tag>::type Point; + typedef Point result_type; + typedef typename Get_type<R_, FT_tag>::type FT; + template <class Iter> + result_type operator()(Iter f, Iter e)const{ + typedef typename Get_type<R_, Point_tag>::type Point; + typedef typename R_::LA LA; + typename Get_functor<R_, Compute_point_cartesian_coordinate_tag>::type c(this->kernel()); + typename Get_functor<R_, Construct_ttag<Point_tag> >::type cp(this->kernel()); + typename Get_functor<R_, Point_dimension_tag>::type pd(this->kernel()); + typename Get_functor<R_, Squared_distance_to_origin_tag>::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<d;++j) { + m(i,j)=2*(c(p,j)-c(p0,j)); + b[i] = sdo(p) - n0; + } + } + CGAL_assertion (i == d); + Vec res = typename CVec::Dimension()(d);; + //std::cout << "Mat: " << m << "\n Vec: " << one << std::endl; + LA::solve(res, CGAL_MOVE(m), CGAL_MOVE(b)); + //std::cout << "Sol: " << res << std::endl; + return cp(d,LA::vector_begin(res),LA::vector_end(res)); + } + else + { + /* + * Matrix P=(p1, p2, ...) (each point as a column) + * Matrix Q=2*t(p2-p1,p3-p1, ...) (each vector as a line) + * Matrix M: QP, adding a line of 1 at the top + * Vector B: (1, p2^2-p1^2, p3^2-p1^2, ...) + * Solve ML=B, the center of the sphere is PL + * + * It would likely be faster to write P then transpose, multiply, + * etc instead of doing it by hand. + */ + // TODO: check for degenerate cases? + + typedef typename R_::Max_ambient_dimension D2; + typedef typename R_::LA::template Rebind_dimension<Dynamic_dimension_tag,D2>::Other LAd; + typedef typename LAd::Square_matrix Matrix; + typedef typename LAd::Vector Vec; + typename Get_functor<R_, Scalar_product_tag>::type sp(this->kernel()); + int k=static_cast<int>(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<k;++i){ + b(i)-=b(0); + for(j=0;j<k;++j){ + m(i,j)=2*(m(i,j)-m(0,j)); + } + } + for(j=0;j<k;++j) m(0,j)=1; + b(0)=1; + + LAd::solve(l,CGAL_MOVE(m),CGAL_MOVE(b)); + + typename LA::Vector center=typename LA::Construct_vector::Dimension()(d); + for(i=0;i<d;++i) center(i)=0; + j=0; + for(Iter f2=f;f2!=e;++f2,++j){ + for(i=0;i<d;++i){ + center(i)+=l(j)*c(*f2,i); + } + } + + return cp(LA::vector_begin(center),LA::vector_end(center)); + } + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Construct_circumcenter_tag,(CartesianDKernelFunctors::Construct_circumcenter<K>),(Point_tag),(Construct_ttag<Point_tag>,Compute_point_cartesian_coordinate_tag,Scalar_product_tag,Squared_distance_to_origin_tag,Point_dimension_tag)); + +namespace CartesianDKernelFunctors { +template <class R_> struct Squared_circumradius : Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Squared_circumradius) + typedef typename Get_type<R_, FT_tag>::type result_type; + template <class Iter> + result_type operator()(Iter f, Iter e)const{ + typename Get_functor<R_, Construct_circumcenter_tag>::type cc(this->kernel()); + typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel()); + return sd(cc(f, e), *f); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Squared_circumradius_tag,(CartesianDKernelFunctors::Squared_circumradius<K>),(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<class R_> struct Side_of_bounded_sphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Side_of_bounded_sphere) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Bounded_side_tag>::type result_type; + + template<class Iter> + result_type operator()(Iter f, Iter const& e) const { + Point const& p0 = *f++; // *--e ? + typename Get_functor<R, Point_dimension_tag>::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<class Iter> + result_type operator()(Iter const& f, Iter const& e, Point const& p0) const { + typename Get_functor<R, Side_of_oriented_sphere_tag>::type sos (this->kernel()); + typename Get_functor<R, Orientation_of_points_tag>::type op (this->kernel()); + // enum_cast is not very generic, but since this function isn't supposed to remain like this... + return enum_cast<Bounded_side> (sos (f, e, p0) * op (f, e)); + } + +#ifdef CGAL_CXX11 + template <class...U,class=typename std::enable_if<(sizeof...(U)>=4)>::type> + result_type operator()(U&&...u) const { + return operator()({std::forward<U>(u)...}); + } + + template <class P> + result_type operator()(std::initializer_list<P> 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<K>),(Point_tag),(Side_of_oriented_sphere_tag,Orientation_of_points_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Side_of_bounded_circumsphere : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Side_of_bounded_circumsphere) + typedef typename Get_type<R_, Bounded_side_tag>::type result_type; + + template<class Iter, class P> + result_type operator()(Iter f, Iter const& e, P const& p0) const { + // TODO: Special case when the dimension is full. + typename Get_functor<R_, Construct_circumcenter_tag>::type cc(this->kernel()); + typename Get_functor<R_, Compare_distance_tag>::type cd(this->kernel()); + + return enum_cast<Bounded_side>(cd(cc(f, e), *f, p0)); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Side_of_bounded_circumsphere_tag,(CartesianDKernelFunctors::Side_of_bounded_circumsphere<K>),(Point_tag),(Squared_distance_tag,Construct_circumcenter_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Point_to_vector : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Point_to_vector) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<K>),(Point_tag,Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Vector_to_point : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Vector_to_point) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Point_tag> >::type CP; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<K>),(Point_tag,Vector_tag),(Construct_ttag<Point_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Opposite_vector : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Opposite_vector) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<RT>()),make_transforming_iterator(ci(v,End_tag()),std::negate<RT>())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Opposite_vector_tag,(CartesianDKernelFunctors::Opposite_vector<K>),(Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Scaled_vector : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Scaled_vector) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<FT>(s)),make_transforming_iterator(ci(v,End_tag()),Scale<FT>(s))); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Scaled_vector_tag,(CartesianDKernelFunctors::Scaled_vector<K>),(Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Sum_of_vectors : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Sum_of_vectors) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<RT>()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::plus<RT>())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Sum_of_vectors_tag,(CartesianDKernelFunctors::Sum_of_vectors<K>),(Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Difference_of_vectors : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Difference_of_vectors) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<RT>()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::minus<RT>())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Difference_of_vectors_tag,(CartesianDKernelFunctors::Difference_of_vectors<K>),(Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Translated_point : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Translated_point) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Point_tag> >::type CP; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::type CVI; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<RT>()),make_transforming_pair_iterator(cpi(a,End_tag()),cvi(b,End_tag()),std::plus<RT>())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Translated_point_tag,(CartesianDKernelFunctors::Translated_point<K>),(Point_tag, Vector_tag),(Construct_ttag<Point_tag>, Construct_ttag<Vector_cartesian_const_iterator_tag>, Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Difference_of_points : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Difference_of_points) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_tag> >::type CV; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<RT>()),make_transforming_pair_iterator(ci(a,End_tag()),ci(b,End_tag()),std::minus<RT>())); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Difference_of_points_tag,(CartesianDKernelFunctors::Difference_of_points<K>),(Point_tag, Vector_tag),(Construct_ttag<Vector_tag>, Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Midpoint : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Midpoint) + typedef R_ R; + typedef typename Get_type<R, FT_tag>::type FT; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Point_tag> >::type CP; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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,RT,FT> { + 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<FT,int> half(2); + //return CP(this->kernel())(make_transforming_iterator(make_transforming_pair_iterator(ci.begin(a),ci.begin(b),std::plus<FT>()),half),make_transforming_iterator(make_transforming_pair_iterator(ci.end(a),ci.end(b),std::plus<FT>()),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<K>),(Point_tag),(Construct_ttag<Point_tag>, Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Squared_length : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Squared_length) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<RT>::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<K>),(Vector_tag),(Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Squared_distance_to_origin : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Squared_distance_to_origin) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<RT>::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<K>),(Point_tag),(Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Squared_distance : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Squared_distance) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::type CI; + typedef RT result_type; + typedef Point first_argument_type; + typedef Point second_argument_type; + struct Sq_diff : std::binary_function<RT,RT,RT> { + 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<K>),(Point_tag),(Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Scalar_product : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Scalar_product) + typedef R_ R; + typedef typename Get_type<R, RT_tag>::type RT; + typedef typename Get_type<R, Vector_tag>::type Vector; + typedef typename Get_functor<R, Construct_ttag<Vector_cartesian_const_iterator_tag> >::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<RT> 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<K>),(Vector_tag),(Construct_ttag<Vector_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Compare_distance : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Compare_distance) + typedef R_ R; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_functor<R, Squared_distance_tag>::type CSD; + typedef typename Get_type<R, Comparison_result_tag>::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<K>),(Point_tag),(Squared_distance_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Less_point_cartesian_coordinate : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Less_point_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::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<Cc> Is_exact; + + template<class V,class W,class I> + result_type operator()(V const&a, W const&b, I i)const{ + Cc c(this->kernel()); + return c(a,i)<c(b,i); + } +}; +} + +CGAL_KD_DEFAULT_FUNCTOR(Less_point_cartesian_coordinate_tag,(CartesianDKernelFunctors::Less_point_cartesian_coordinate<K>),(),(Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Compare_point_cartesian_coordinate : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Compare_point_cartesian_coordinate) + typedef R_ R; + typedef typename Get_type<R, Comparison_result_tag>::type result_type; + typedef typename Get_functor<R, Compute_point_cartesian_coordinate_tag>::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<Cc> Is_exact; + + template<class V,class W,class I> + 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<K>),(),(Compute_point_cartesian_coordinate_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Compare_lexicographically : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Compare_lexicographically) + typedef R_ R; + typedef typename Get_type<R, Comparison_result_tag>::type result_type; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<CI> Is_exact; + + template<class V,class W> + 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<result_type>(); + 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<K>),(),(Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Less_lexicographically : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Less_lexicographically) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Compare_lexicographically_tag>::type CL; + typedef typename CGAL::Is_exact<CL> Is_exact; + + template <class V, class W> + 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<K>),(),(Compare_lexicographically_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Less_or_equal_lexicographically : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Less_or_equal_lexicographically) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Compare_lexicographically_tag>::type CL; + typedef typename CGAL::Is_exact<CL> Is_exact; + + template <class V, class W> + 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<K>),(),(Compare_lexicographically_tag)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Equal_points : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Equal_points) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Construct_ttag<Point_cartesian_const_iterator_tag> >::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<CI> Is_exact; + + template<class V,class W> + 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<K>),(),(Construct_ttag<Point_cartesian_const_iterator_tag>)); + +namespace CartesianDKernelFunctors { +template<class R_> struct Oriented_side : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Oriented_side) + typedef R_ R; + typedef typename Get_type<R, Oriented_side_tag>::type result_type; + typedef typename Get_type<R, Point_tag>::type Point; + typedef typename Get_type<R, Hyperplane_tag>::type Hyperplane; + typedef typename Get_type<R, Sphere_tag>::type Sphere; + typedef typename Get_functor<R, Value_at_tag>::type VA; + typedef typename Get_functor<R, Hyperplane_translation_tag>::type HT; + typedef typename Get_functor<R, Squared_distance_tag>::type SD; + typedef typename Get_functor<R, Squared_radius_tag>::type SR; + typedef typename Get_functor<R, Center_of_sphere_tag>::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<K>),(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<class R_> struct Has_on_positive_side : private Store_kernel<R_> { + CGAL_FUNCTOR_INIT_STORE(Has_on_positive_side) + typedef R_ R; + typedef typename Get_type<R, Bool_tag>::type result_type; + typedef typename Get_functor<R, Oriented_side_tag>::type OS; + + template <class Obj, class Pt> + 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<K>),(),(Oriented_side_tag)); + +} +#include <CGAL/NewKernel_d/Coaffine.h> +#endif // CGAL_KERNEL_D_FUNCTION_OBJECTS_CARTESIAN_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/functor_properties.h new file mode 100644 index 00000000..c25c4e2b --- /dev/null +++ b/src/common/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 <boost/mpl/has_xxx.hpp> +#include <CGAL/tags.h> +namespace CGAL { + +#define CGAL_STRAWBERRY(Is_pretty) \ + namespace internal { \ + BOOST_MPL_HAS_XXX_TRAIT_DEF(Is_pretty) \ + } \ + template<class T,bool=internal::has_##Is_pretty<T>::value> \ + struct Is_pretty : boost::false_type {}; \ + template<class T> \ + struct Is_pretty<T,true> : 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/src/common/include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/functor_tags.h new file mode 100644 index 00000000..b8e17886 --- /dev/null +++ b/src/common/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 <CGAL/tags.h> // for Null_tag +#include <CGAL/NewKernel_d/utils.h> +#ifdef CGAL_CXX11 +#include <type_traits> +#include <utility> +#endif +#include <boost/type_traits.hpp> +#include <boost/mpl/has_xxx.hpp> +#include <boost/mpl/not.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/vector.hpp> +#include <boost/mpl/empty.hpp> +#include <boost/mpl/front.hpp> +#include <boost/mpl/pop_front.hpp> +namespace CGAL { + + // Find a better place for this later + + template <class K, class T, class=void> struct Get_type + : K::template Type<T> {}; + template <class K, class F, class O=void, class=void> struct Get_functor + : K::template Functor<F, O> {}; +#ifdef CGAL_CXX11 + template <class K, class T> using Type = typename Get_type<K, T>::type; + template <class K, class T> using Functor = typename Get_functor<K, T>::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 {}; + + template<class>struct Construct_ttag {}; + template<class>struct Convert_ttag {}; + + template <class K, class F, class=void, class=void> struct Get_functor_category { typedef Misc_tag type; }; + template<class Tg, class Obj, class Base> struct Typedef_tag_type; + //template<class Kernel, class Tg> struct Read_tag_type {}; + + template<class Kernel, class Tg> + struct Provides_type + : Has_type_different_from<Get_type<Kernel, Tg>, Null_type> {}; + + template<class Kernel, class Tg, class O=void> + struct Provides_functor + : Has_type_different_from<Get_functor<Kernel, Tg, O>, Null_functor> {}; + + template<class K, class List, bool=boost::mpl::empty<List>::type::value> + struct Provides_functors : boost::mpl::and_ < + Provides_functor<K, typename boost::mpl::front<List>::type>, + Provides_functors<K, typename boost::mpl::pop_front<List>::type> > {}; + template<class K, class List> + struct Provides_functors<K, List, true> : boost::true_type {}; + + template<class K, class List, bool=boost::mpl::empty<List>::type::value> + struct Provides_types : boost::mpl::and_ < + Provides_type<K, typename boost::mpl::front<List>::type>, + Provides_types<K, typename boost::mpl::pop_front<List>::type> > {}; + template<class K, class List> + struct Provides_types<K, List, true> : boost::true_type {}; + + namespace internal { BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_Type,template Type<Null_tag>,false) } + template<class Kernel, class Tg, + bool = internal::has_Type<Kernel>::value /* false */> + struct Provides_type_i : boost::false_type {}; + template<class Kernel, class Tg> + struct Provides_type_i <Kernel, Tg, true> + : Has_type_different_from<typename Kernel::template Type<Tg>, Null_type> {}; + + //// This version does not like Functor<T,bool=false> + //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<Null_tag>,false) } + + template<class Kernel, class Tg, class O=void, + bool = internal::has_Functor<Kernel>::value /* false */> + struct Provides_functor_i : boost::false_type {}; + template<class Kernel, class Tg, class O> + struct Provides_functor_i <Kernel, Tg, O, true> + : Has_type_different_from<typename Kernel::template Functor<Tg, O>, Null_functor> {}; + + // TODO: Refine this a bit. + template <class K, class T, class D=void, + //bool=Provides_functor<K,T>::value, + //bool=Provides_functor_i<K,T>::value, + bool = internal::has_Functor<K>::value + > + struct Inherit_functor : K::template Functor<T> {}; + template <class K, class T, class D> + struct Inherit_functor <K, T, D, false> {}; + + template <class K, class T, bool=internal::has_Type<K>::value> + struct Inherit_type : K::template Type<T> {}; + template <class K, class T> + struct Inherit_type <K, T, false> {}; + + struct Number_tag {}; + struct Discrete_tag {}; + struct Object_tag {}; + template <class K, class T, class=void> 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<class Obj,class Base> \ + struct Typedef_tag_type<X##_tag, Obj, Base> : Base { typedef Obj X; }; \ + template<class K, class D> \ + struct Get_type_category <K, X##_tag, D> { 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<class Kernel> + //struct Provides_tag_type<Kernel, X##_tag> : has_object::has_##X<Kernel> {}; + //template<class Kernel> + //struct Read_tag_type<Kernel, X##_tag> { 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<K, FT_tag>::type),(),()); +// CGAL_KD_DEFAULT_TYPE(FT_tag,(CGAL::Quotient<typename Get_type<K, RT_tag>::type>),(),()); + +#define CGAL_SMURF2(A,B) CGAL_KD_DEFAULT_TYPE(A##_tag,(typename Same_uncertainty_nt<B, typename Get_type<K,RT_tag>::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<class> struct is_NT_tag { enum { value = false }; }; + template<> struct is_NT_tag<FT_tag> { enum { value = true }; }; + template<> struct is_NT_tag<RT_tag> { enum { value = true }; }; + + template<class> 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 {}; \ + template<class A,class B,class C>struct Get_functor_category<A,X##_tag,B,C>{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<X##_tag> { \ + enum { is_iterator = true, has_nth_element = true }; \ + typedef Y##_tag value_tag; \ + typedef Z##_tag nth_element; \ + typedef C##_tag container; \ + }; \ + template<class Obj,class Base> \ + struct Typedef_tag_type<X##_tag, Obj, Base> : Base { typedef Obj X; } + + //namespace has_object { BOOST_MPL_HAS_XXX_TRAIT_DEF(X) } + //template<class Kernel> + //struct Provides_tag_type<Kernel, X##_tag> : has_object::has_##X<Kernel> {}; + //template<class Kernel> + //struct Read_tag_type<Kernel, X##_tag> { 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 + + template<class>struct map_result_tag{typedef Null_type type;}; + template<class T>struct map_result_tag<Construct_ttag<T> >{typedef T type;}; + + template<class A,class T,class B,class C>struct Get_functor_category<A,Construct_ttag<T>,B,C> : + boost::mpl::if_c<iterator_tag_traits<T>::is_iterator, + Construct_iterator_tag, + Construct_tag> {}; + + // Really? + template<class A,class T,class B,class C>struct Get_functor_category<A,Convert_ttag<T>,B,C>{typedef Misc_tag type;}; + +#define CGAL_DECL_CONSTRUCT(X,Y) struct X##_tag {}; \ + template<>struct map_result_tag<X##_tag>{typedef Y##_tag type;}; \ + template<class A,class B,class C>struct Get_functor_category<A,X##_tag,B,C>{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<X##_tag>{typedef Y##_tag type;}; \ + template<>struct map_functor_type<X##_tag>{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) \ + template<class A,class B,class C>struct Get_functor_category<A,X##_tag,B,C>{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 {}; \ + template<class A,class B,class C>struct Get_functor_category<A,X##_tag,B,C>{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<class> struct Preserved_by_non_linear_extra_coordinate + : boost::false_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_extra_dimension_tag> : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_determinant_of_vectors_tag> : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_determinant_of_points_tag> : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_determinant_of_iterator_to_vectors_tag> : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_determinant_of_iterator_to_points_tag> : boost::true_type {}; + template<> struct Preserved_by_non_linear_extra_coordinate + <Has_determinant_of_vectors_omit_last_tag> : boost::true_type {}; + + // Kernel properties + struct Point_stores_squared_distance_to_origin_tag {}; + +} +#endif // CGAL_FUNCTOR_TAGS_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/static_int.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/static_int.h new file mode 100644 index 00000000..21858804 --- /dev/null +++ b/src/common/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 <CGAL/constant.h> + +namespace CGAL { +template <class NT> struct static_zero { + operator NT() const { return constant<NT,0>(); } +}; +template <class NT> struct static_one { + operator NT() const { return constant<NT,1>(); } +}; + +template <class NT> static_zero<NT> operator-(static_zero<NT>) { return static_zero<NT>(); } + +template <class NT> NT operator+(NT const& x, static_zero<NT>) { return x; } +template <class NT> NT operator+(static_zero<NT>, NT const& x) { return x; } +template <class NT> static_zero<NT> operator+(static_zero<NT>, static_zero<NT>) { return static_zero<NT>(); } +template <class NT> static_one<NT> operator+(static_zero<NT>, static_one<NT>) { return static_one<NT>(); } +template <class NT> static_one<NT> operator+(static_one<NT>, static_zero<NT>) { return static_one<NT>(); } + +template <class NT> NT operator-(NT const& x, static_zero<NT>) { return x; } +template <class NT> NT operator-(static_zero<NT>, NT const& x) { return -x; } +template <class NT> static_zero<NT> operator-(static_zero<NT>, static_zero<NT>) { return static_zero<NT>(); } +template <class NT> static_zero<NT> operator-(static_one<NT>, static_one<NT>) { return static_zero<NT>(); } +template <class NT> static_one<NT> operator-(static_one<NT>, static_zero<NT>) { return static_one<NT>(); } + +template <class NT> NT operator*(NT const& x, static_one<NT>) { return x; } +template <class NT> NT operator*(static_one<NT>, NT const& x) { return x; } +template <class NT> static_zero<NT> operator*(NT const&, static_zero<NT>) { return static_zero<NT>(); } +template <class NT> static_zero<NT> operator*(static_zero<NT>, NT const&) { return static_zero<NT>(); } +template <class NT> static_zero<NT> operator*(static_zero<NT>, static_zero<NT>) { return static_zero<NT>(); } +template <class NT> static_one<NT> operator*(static_one<NT>, static_one<NT>) { return static_one<NT>(); } +template <class NT> static_zero<NT> operator*(static_zero<NT>, static_one<NT>) { return static_zero<NT>(); } +template <class NT> static_zero<NT> operator*(static_one<NT>, static_zero<NT>) { return static_zero<NT>(); } + +template <class NT> NT operator/(NT const& x, static_one<NT>) { return x; } +template <class NT> static_zero<NT> operator/(static_zero<NT>, NT const&) { return static_zero<NT>(); } +template <class NT> static_zero<NT> operator/(static_zero<NT>, static_one<NT>) { return static_zero<NT>(); } +template <class NT> static_one<NT> operator/(static_one<NT>, static_one<NT>) { return static_one<NT>(); } + +} +#endif // CGAL_STATIC_INT_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/store_kernel.h new file mode 100644 index 00000000..253e1282 --- /dev/null +++ b/src/common/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 <CGAL/assertions.h> +#include <boost/type_traits/is_empty.hpp> + +namespace CGAL { +namespace internal { +BOOST_MPL_HAS_XXX_TRAIT_DEF(Do_not_store_kernel) +template<class T,bool=boost::is_empty<T>::value,bool=has_Do_not_store_kernel<T>::value> struct Do_not_store_kernel { + enum { value=false }; + typedef Tag_false type; +}; +template<class T> struct Do_not_store_kernel<T,true,false> { + enum { value=true }; + typedef Tag_true type; +}; +template<class T,bool b> struct Do_not_store_kernel<T,b,true> { + typedef typename T::Do_not_store_kernel type; + enum { value=type::value }; +}; +} + +template<class R_,bool=internal::Do_not_store_kernel<R_>::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<class R_> +struct Store_kernel<R_,false> { + 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<class R_,bool=internal::Do_not_store_kernel<R_>::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<class R_> +struct Store_kernel2<R_,false> { + 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<R_>) +#define CGAL_FUNCTOR_INIT_IGNORE(X) \ + X(){} \ + X(R_ const&){} + +#endif // CGAL_STORE_KERNEL_H diff --git a/src/common/include/gudhi_patches/CGAL/NewKernel_d/utils.h b/src/common/include/gudhi_patches/CGAL/NewKernel_d/utils.h new file mode 100644 index 00000000..238a2230 --- /dev/null +++ b/src/common/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 <CGAL/config.h> + +#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 <type_traits> +#include <utility> +#define CGAL_FORWARDABLE(T) T&& +#define CGAL_FORWARD(T,t) std::forward<T>(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 <boost/utility/enable_if.hpp> +#include <boost/preprocessor/repetition.hpp> +#include <CGAL/Rational_traits.h> +#include <CGAL/tuple.h> +#include <boost/mpl/has_xxx.hpp> +#include <boost/mpl/not.hpp> +#include <boost/type_traits.hpp> + +#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 <class T, class No, bool=internal::has_type<T>::value /*false*/> +struct Has_type_different_from : boost::false_type {}; +template <class T, class No> +struct Has_type_different_from <T, No, true> +: boost::mpl::not_<boost::is_same<typename T::type, No> > {}; + + + template <class T> 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<class A,class B> 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<class T,class U,class V> inline + typename std::conditional<std::is_arithmetic<T>::value&&std::is_arithmetic<typename std::remove_reference<U>::type>::value,T,U&&>::type + forward_safe(V&& u) { return std::forward<U>(u); } +#else + template<class T,class U> inline U const& forward_safe(U const& u) { + return u; + } +#endif + +#ifdef CGAL_CXX11 + template<class...> struct Constructible_from_each; + template<class To,class From1,class...From> struct Constructible_from_each<To,From1,From...>{ + enum { value=std::is_convertible<From1,To>::value&&Constructible_from_each<To,From...>::value }; + }; + template<class To> struct Constructible_from_each<To>{ + enum { value=true }; + }; +#else +// currently only used in C++0X code +#endif + + template<class T> struct Scale { +#ifndef CGAL_CXX11 + template<class> struct result; + template<class FT> struct result<Scale(FT)> { + typedef FT type; + }; +#endif + T const& scale; + Scale(T const& t):scale(t){} + template<class FT> +#ifdef CGAL_CXX11 + auto operator()(FT&& x)const->decltype(scale*std::forward<FT>(x)) +#else + FT operator()(FT const& x)const +#endif + { + return scale*CGAL_FORWARD(FT,x); + } + }; + template<class NT,class T> struct Divide { +#if !defined(CGAL_CXX11) || !defined(BOOST_RESULT_OF_USE_DECLTYPE) + // requires boost > 1.44 + // shouldn't be needed with C++0X + //template<class> struct result; + //template<class FT> struct result<Divide(FT)> { + // typedef FT type; + //}; + typedef NT result_type; +#endif + T const& scale; + Divide(T const& t):scale(t){} + template<class FT> +#ifdef CGAL_CXX11 + //FIXME: gcc complains for Gmpq + //auto operator()(FT&& x)const->decltype(Rational_traits<NT>().make_rational(std::forward<FT>(x),scale)) + NT operator()(FT&& x)const +#else + NT operator()(FT const& x)const +#endif + { + return Rational_traits<NT>(). + make_rational(CGAL_FORWARD(FT,x),scale); + } + }; + + template <class NT> struct has_cheap_constructor : boost::is_arithmetic<NT>{}; + template <bool p> struct has_cheap_constructor<Interval_nt<p> > { + 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<class A,class B> +#ifdef CGAL_CXX11 + auto operator()(A&&a,B&&b)const->decltype(std::forward<A>(a)*std::forward<B>(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<class A,class B> +#ifdef CGAL_CXX11 + auto operator()(A&&a,B&&b)const->decltype(std::forward<A>(a)/std::forward<B>(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<class T> struct decay : boost::remove_cv<typename boost::decay<T>::type> {}; +#endif + + template<class T,class U> struct Type_copy_ref { typedef U type; }; + template<class T,class U> struct Type_copy_ref<T&,U> { typedef U& type; }; +#ifdef CGAL_CXX11 + template<class T,class U> struct Type_copy_ref<T&&,U> { typedef U&& type; }; +#endif + template<class T,class U> struct Type_copy_cv { typedef U type; }; + template<class T,class U> struct Type_copy_cv<T const,U> { typedef U const type; }; + template<class T,class U> struct Type_copy_cv<T volatile,U> { typedef U volatile type; }; + template<class T,class U> struct Type_copy_cv<T const volatile,U> { typedef U const volatile type; }; + + template<class T,class U> struct Type_copy_cvref : + Type_copy_ref<T,typename Type_copy_cv<typename boost::remove_reference<T>::type,U>::type> {}; + + struct Dereference_functor { + template<class> struct result{}; + template<class It> struct result<Dereference_functor(It)> { + typedef typename std::iterator_traits<It>::reference type; + }; + template<class It> typename result<Dereference_functor(It)>::type + operator()(It const&i)const{ + return *i; + } + }; + +#ifdef CGAL_CXX11 + template<int...> struct Indices{}; + template<class> struct Next_increasing_indices; + template<int...I> struct Next_increasing_indices<Indices<I...> > { + typedef Indices<I...,sizeof...(I)> type; + }; + template<int N> struct N_increasing_indices { + typedef typename Next_increasing_indices<typename N_increasing_indices<N-1>::type>::type type; + }; + template<> struct N_increasing_indices<0> { typedef Indices<> type; }; + namespace internal { + template<class F,class...U,int...I> inline typename std::result_of<F&&(U...)>::type + do_call_on_tuple_elements(F&&f, std::tuple<U...>&&t, Indices<I...>&&) { + return f(std::get<I>(std::move(t))...); + } + } // internal + template<class/*result type, ignored*/,class F,class...U> + inline typename std::result_of<F&&(U...)>::type + call_on_tuple_elements(F&&f, std::tuple<U...>&&t) { + return internal::do_call_on_tuple_elements(std::forward<F>(f),std::move(t), + typename N_increasing_indices<sizeof...(U)>::type()); + } +#else +#define CGAL_VAR(Z,N,_) cpp0x::get<N>(t) +#define CGAL_CODE(Z,N,_) template<class Res, class F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N,class U)> \ + inline Res call_on_tuple_elements(F const&f, \ + cpp0x::tuple<BOOST_PP_ENUM_PARAMS(N,U)> const&t) { \ + return f(BOOST_PP_ENUM(N,CGAL_VAR,)); \ + } + template<class Res, class F> + 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<class A> struct Factory { + typedef A result_type; +#ifdef CGAL_CXX11 + template<class...U> result_type operator()(U&&...u)const{ + return A(std::forward<U>(u)...); + } +#else + result_type operator()()const{ + return A(); + } +#define CGAL_CODE(Z,N,_) template<BOOST_PP_ENUM_PARAMS(N,class U)> \ + 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 <class K, class O> \ + struct Get_functor<K, Tg, O, \ + typename boost::mpl::if_c< \ + Provides_functor_i<K, Tg, O>::value \ + || !Provides_types<K, boost::mpl::vector<CGAL_STRIP_PAREN_ ReqTyp> >::value \ + || !Provides_functors<K, boost::mpl::vector<CGAL_STRIP_PAREN_ ReqFun> >::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 <class K> \ + struct Get_type<K, Tg, \ + typename boost::mpl::if_c< \ + Provides_type_i<K, Tg>::value \ + || !Provides_types<K, boost::mpl::vector<CGAL_STRIP_PAREN_ ReqTyp> >::value \ + || !Provides_functors<K, boost::mpl::vector<CGAL_STRIP_PAREN_ ReqFun> >::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/src/common/include/gudhi_patches/CGAL/Regular_triangulation.h b/src/common/include/gudhi_patches/CGAL/Regular_triangulation.h new file mode 100644 index 00000000..111c6ac9 --- /dev/null +++ b/src/common/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 <CGAL/Triangulation.h> +#include <CGAL/Dimension.h> +#include <CGAL/Default.h> +#include <CGAL/spatial_sort.h> +#include <CGAL/Regular_triangulation_traits_adapter.h> + +#include <boost/property_map/function_property_map.hpp> + +namespace CGAL { + +template< typename Traits_, typename TDS_ = Default > +class Regular_triangulation +: public Triangulation< + Regular_triangulation_traits_adapter<Traits_>, + typename Default::Get< + TDS_, + Triangulation_data_structure< + typename Regular_triangulation_traits_adapter<Traits_>::Dimension, + Triangulation_vertex<Regular_triangulation_traits_adapter<Traits_> >, + Triangulation_full_cell<Regular_triangulation_traits_adapter<Traits_> > + > + >::type> +{ + typedef Regular_triangulation_traits_adapter<Traits_> RTTraits; + typedef typename RTTraits::Dimension Maximal_dimension_; + typedef typename Default::Get< + TDS_, + Triangulation_data_structure< + Maximal_dimension_, + Triangulation_vertex<RTTraits>, + Triangulation_full_cell<RTTraits> + > >::type TDS; + typedef Triangulation<RTTraits, TDS> Base; + typedef Regular_triangulation<Traits_, TDS_> 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<Flat_orientation_d>* 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<Flat_orientation_d>& x, + Construct_flat_orientation_d const&y, + In_flat_power_side_of_power_sphere_d const&z) + : fop(&x), cfo(y), ifpt(z) {} + + template<class Iter> + 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<int, const Flat_orientation_d *> &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<Weighted_point> 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<OrientationPredicate>(p_, s, ori_); + } + else + { + typedef typename Full_cell::Vertex_handle_const_iterator VHCI; + typedef Substitute_point_in_vertex_iterator<VHCI> 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<typename InputIterator> + 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<typename InputIterator, typename OutputIterator> + 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<typename InputIterator> + 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<Coaffine_orientation_d, Power_side_of_power_sphere_for_non_maximal_dim_d> + Conflict_pred_in_subspace; + typedef Conflict_predicate<Orientation_d, Power_side_of_power_sphere_d> + Conflict_pred_in_fullspace; + typedef Conflict_traversal_predicate<Conflict_pred_in_subspace> + Conflict_traversal_pred_in_subspace; + typedef Conflict_traversal_predicate<Conflict_pred_in_fullspace> + Conflict_traversal_pred_in_fullspace; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MEMBER VARIABLES + std::vector<Weighted_point> 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<Traits, TDS>::Full_cell_handle +Regular_triangulation<Traits, TDS> +::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<Full_cell_handle> Simplices; + Simplices simps; + std::back_insert_iterator<Simplices> out(simps); + tds().incident_full_cells(v, out); + typedef std::set<Vertex_handle> 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<Geom_traits, Vertex_handle> Dark_vertex_base; + typedef Triangulation_full_cell< + Geom_traits, + internal::Triangulation::Dark_full_cell_data<TDS> > Dark_full_cell_base; + typedef Triangulation_data_structure<Maximal_dimension, + Dark_vertex_base, + Dark_full_cell_base + > Dark_tds; + typedef Regular_triangulation<Traits, Dark_tds> 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<int, const Flat_orientation_d *>(current_dimension(), flat_orientation_.get_ptr()) + : std::pair<int, const Flat_orientation_d *>(std::numeric_limits<int>::max(), NULL) ); + + Dark_s_handle dark_s; + Dark_v_handle dark_v; + typedef std::map<Vertex_handle, Dark_v_handle> 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_s_handle> Dark_full_cells; + Dark_full_cells conflict_zone; + std::back_insert_iterator<Dark_full_cells> 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<std::pair<Facet, Dark_facet> > 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<Facet, Dark_facet> 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<Traits, TDS> +::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<Traits, TDS>::Vertex_handle +Regular_triangulation<Traits, TDS> +::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<Traits, TDS>::Vertex_handle +Regular_triangulation<Traits, TDS> +::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<Traits, TDS>::Vertex_handle +Regular_triangulation<Traits, TDS> +::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<Traits, TDS>::Vertex_handle +Regular_triangulation<Traits, TDS> +::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_handle> 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<Full_cell_h_vector> 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<Vertex_handle> 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<Traits, TDS> +::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<const Weighted_point *> 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<Self>(*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<Self>, + 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<Traits, TDS> +::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<Traits, TDS>::Facet +Regular_triangulation<Traits, TDS> +::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<Traits, TDS> +::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/src/common/include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h b/src/common/include/gudhi_patches/CGAL/Regular_triangulation_traits_adapter.h new file mode 100644 index 00000000..78bb95a6 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> + +#include <boost/iterator/transform_iterator.hpp> + +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 K> +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 <typename ForwardIterator> + 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 <typename ForwardIterator> + 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 <typename ForwardIterator> + 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 <typename ForwardIterator> + 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/src/common/include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h b/src/common/include/gudhi_patches/CGAL/TDS_full_cell_default_storage_policy.h new file mode 100644 index 00000000..9a6030e5 --- /dev/null +++ b/src/common/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 <CGAL/Dimension.h> +#include <CGAL/Compact_container.h> +#include <CGAL/internal/Static_or_dynamic_array.h> + +#include <boost/cstdint.hpp> + +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<Dimen>::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<Xor_type>(&(*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<Xor_type>(&(*vertices_[i])); + Vertex_handle mirror; + typedef typename Vertex_handle::pointer pointer; + // mirror.set_pointer(reinterpret_cast<pointer>(opp_vertex)); + mirror = Compact_container<typename Vertex_handle::value_type> + ::s_iterator_to(*(reinterpret_cast<pointer>(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/src/common/include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h b/src/common/include/gudhi_patches/CGAL/TDS_full_cell_mirror_storage_policy.h new file mode 100644 index 00000000..095dfe68 --- /dev/null +++ b/src/common/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 <CGAL/TDS_full_cell_default_storage_policy.h> + +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/src/common/include/gudhi_patches/CGAL/Triangulation.h b/src/common/include/gudhi_patches/CGAL/Triangulation.h new file mode 100644 index 00000000..906df92e --- /dev/null +++ b/src/common/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 <CGAL/internal/Triangulation/utilities.h> +#include <CGAL/Triangulation_data_structure.h> +#include <CGAL/Triangulation_full_cell.h> +#include <CGAL/Triangulation_vertex.h> +#include <CGAL/Iterator_project.h> +#include <CGAL/spatial_sort.h> +#include <CGAL/Dimension.h> +#include <CGAL/iterator.h> +#include <CGAL/Default.h> +#include <CGAL/Random.h> + +#include <boost/iterator/filter_iterator.hpp> +#include <boost/iterator/transform_iterator.hpp> + +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 VertexHandleConstIter> +class Substitute_point_in_vertex_iterator +{ + typedef typename std::iterator_traits<VertexHandleConstIter>::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<TDS_, Triangulation_data_structure + < Maximal_dimension_, + Triangulation_vertex<TriangulationTraits>, + Triangulation_full_cell<TriangulationTraits> > + >::type TDS; + typedef Triangulation<TriangulationTraits, TDS_> 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<Flat_orientation_d>* fop; + Construct_flat_orientation_d cfo; + In_flat_orientation_d ifo; + + Coaffine_orientation_d( + boost::optional<Flat_orientation_d>& x, + Construct_flat_orientation_d const&y, + In_flat_orientation_d const&z) + : fop(&x), cfo(y), ifo(z) {} + + template<class Iter> + 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<Finiteness_predicate, Vertex_iterator> + Finite_vertex_iterator; + typedef boost::filter_iterator<Finiteness_predicate, Vertex_const_iterator> + Finite_vertex_const_iterator; + typedef boost::filter_iterator<Finiteness_predicate, Full_cell_iterator> + Finite_full_cell_iterator; + typedef boost::filter_iterator<Finiteness_predicate, Full_cell_const_iterator> + Finite_full_cell_const_iterator; + typedef boost::filter_iterator<Finiteness_predicate, Facet_iterator> + Finite_facet_iterator; + +protected: // DATA MEMBERS + + Triangulation_ds tds_; + const Geom_traits kernel_; + Vertex_handle infinity_; + mutable std::vector<Oriented_side> orientations_; + mutable boost::optional<Flat_orientation_d> 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<int>::max() otherwise) + std::pair<int, const Flat_orientation_d *> 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<Vertex_handle, Point> + > 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<Full_cell_handle, int, int> 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<int>::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<int, const Flat_orientation_d *> &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<int>::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<Self> 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<Point> points(start, end); + spatial_sort(points.begin(), points.end(), geom_traits()); + Full_cell_handle hint = Full_cell_handle(); + typename std::vector<Point>::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<FCH> + { + typedef std::vector<FCH> 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<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<Full_cell_handle> simps; + simps.reserve(64); + std::back_insert_iterator<std::vector<Full_cell_handle> > out(simps); + if( current_dimension() < maximal_dimension() ) + { + Coaffine_orientation_d ori = coaffine_orientation_predicate(); + Outside_convex_hull_traversal_predicate<Coaffine_orientation_d> + 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<Orientation_d> + 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<TT, TDS>::Vertex_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Full_cell_handle +Triangulation<TT, TDS> +::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<Self*>(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<TT, TDS>::Full_cell_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Full_cell_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Full_cell_handle +Triangulation<TT, TDS> +::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<TT, TDS>::Full_cell_handle +Triangulation<TT, TDS> +::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<TT, TDS> +::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<TT, TDS>::are_incident_full_cells_valid(Vertex_const_handle v, bool verbose, int) const +{ + if( current_dimension() <= 0 ) + return true; + typedef std::vector<Full_cell_const_handle> Simps; + Simps simps; + simps.reserve(64); + std::back_insert_iterator<Simps> 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<TT, TDS> & 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<TT, TDS> 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<Vertex_handle> 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<TT, TDS> & 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<TT, TDS> 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<Vertex_handle, int> 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/src/common/include/gudhi_patches/CGAL/Triangulation_data_structure.h b/src/common/include/gudhi_patches/CGAL/Triangulation_data_structure.h new file mode 100644 index 00000000..2493c712 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/Default.h> +#include <CGAL/iterator.h> +#include <CGAL/Compact_container.h> +#include <CGAL/Triangulation_face.h> +#include <CGAL/Triangulation_ds_vertex.h> +#include <CGAL/Triangulation_ds_full_cell.h> +#include <CGAL/internal/Combination_enumerator.h> +#include <CGAL/internal/Triangulation/utilities.h> +#include <CGAL/internal/Triangulation/Triangulation_ds_iterators.h> + +#include <algorithm> +#include <vector> +#include <queue> +#include <set> + +namespace CGAL { + +template< class Dimen, + class Vb = Default, + class Fcb = Default > +class Triangulation_data_structure +{ + typedef Triangulation_data_structure<Dimen, Vb, Fcb> Self; + typedef typename Default::Get<Vb, Triangulation_ds_vertex<> >::type V_base; + typedef typename Default::Get<Fcb, Triangulation_ds_full_cell<> >::type FC_base; + +public: + typedef typename V_base::template Rebind_TDS<Self>::Other Vertex; /* Concept */ + typedef typename FC_base::template Rebind_TDS<Self>::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<Dimen, Vb2, Fcb> Other; + }; + + template < typename Fcb2 > + struct Rebind_full_cell { + typedef Triangulation_data_structure<Dimen, Vb, Fcb2> 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> Vertex_container; + typedef Compact_container<Full_cell> 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<Self> 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<Self> 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<Dimension_tag<D> > + { + static int value(int) { return D; } + }; + +public: + Triangulation_data_structure( int dim=0) /* Concept */ + : dmax_(get_maximal_dimension<Dimen>::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<Vertex_const_handle, Vertex_handle> V_map; + typedef std::map<Full_cell_const_handle, Full_cell_handle> 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<Vertex_const_handle> > + 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<Vertex_const_handle> > + 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<Vertex_const_handle>(), 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<Vertex_const_handle> = std::less<Vertex_const_handle>(), bool = false) const; +#endif + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INPUT / OUTPUT + + std::istream & read_full_cells(std::istream &, const std::vector<Vertex_handle> &); + std::ostream & write_full_cells(std::ostream &, std::map<Vertex_const_handle, int> &) 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<Dim, Vb, Fcb> +::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<Dim, Vb, Fcb> +::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<Dim, Vb, Fcb> +::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<Dim, Vb, Fcb>::Facet +Triangulation_data_structure<Dim, Vb, Fcb> +::gather_full_cells(Full_cell_handle start, + TraversalPredicate & tp, + OutputIterator & out) const /* Concept */ +{ + std::queue<Full_cell_handle> 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<Dim, Vb, Fcb> +::incident_faces(Vertex_const_handle v, int dim, OutputIterator out, + std::less<Vertex_const_handle> cmp, bool upper_faces) const +{ + return incident_faces<OutputIterator, std::less<Vertex_const_handle> >(v, dim, out, cmp, upper_faces); +} +#endif + +template< class Dim, class Vb, class Fcb > +template< typename OutputIterator, typename Comparator > +OutputIterator +Triangulation_data_structure<Dim, Vb, Fcb> +::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<Full_cell_handle> Simplices; + Simplices simps; + simps.reserve(64); + // gather incident full_cells + std::back_insert_iterator<Simplices> sout(simps); + incident_full_cells(v, sout); + // for storing the handles to the vertices of a full_cell + typedef std::vector<Vertex_const_handle> Vertices; + typedef std::vector<int> 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<Self> + Upper_face_comparator; + Upper_face_comparator ufc(dim); + typedef std::set<Face, Upper_face_comparator> 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 <class Dim, class Vb, class Fcb> +typename Triangulation_data_structure<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::collapse_face(const Face & f) /* Concept */ +{ + const int fd = f.face_dimension(); + CGAL_precondition( (1 <= fd ) && (fd < current_dimension())); + std::vector<Full_cell_handle> 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<std::vector<Full_cell_handle> > 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 <class Dim, class Vb, class Fcb> +void +Triangulation_data_structure<Dim, Vb, Fcb> +::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<Full_cell_handle> 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 <class Dim, class Vb, class Fcb> +typename Triangulation_data_structure<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::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 <class Dim, class Vb, class Fcb > +typename Triangulation_data_structure<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::insert_in_face(const Face & f) /* Concept */ +{ + std::vector<Full_cell_handle> simps; + simps.reserve(64); + std::back_insert_iterator<std::vector<Full_cell_handle> > out(simps); + incident_full_cells(f, out); + return insert_in_hole(simps.begin(), simps.end(), Facet(f.full_cell(), f.index(0))); +} +template <class Dim, class Vb, class Fcb > +typename Triangulation_data_structure<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::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 <class Dim, class Vb, class Fcb > +template < typename OutputIterator > +typename Triangulation_data_structure<Dim, Vb, Fcb>::Full_cell_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::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<IITH_task> 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<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::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<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::insert_in_hole(Forward_iterator start, Forward_iterator end, Facet f) /* Concept */ +{ + Emptyset_iterator out; + return insert_in_hole(start, end, f, out); +} + +template <class Dim, class Vb, class Fcb> +void +Triangulation_data_structure<Dim, Vb, Fcb> +::clear_visited_marks(Full_cell_handle start) const // NOT DOCUMENTED +{ + CGAL_precondition(start != Full_cell_handle()); + + std::queue<Full_cell_handle> 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 <class Dim, class Vb, class Fcb> +void Triangulation_data_structure<Dim, Vb, Fcb> +::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<Full_cell_handle> 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 <class Dim, class Vb, class Fcb> +typename Triangulation_data_structure<Dim, Vb, Fcb>::Vertex_handle +Triangulation_data_structure<Dim, Vb, Fcb> +::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 <class Dimen, class Vb, class Fcb> +bool Triangulation_data_structure<Dimen, Vb, Fcb> +::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 <class Dim, class Vb, class Fcb> +template <class OutStream> +void Triangulation_data_structure<Dim, Vb, Fcb> +::write_graph(OutStream & os) +{ + std::vector<std::set<int> > 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<int>::const_iterator nit = edges[i].begin(); + nit != edges[i].end(); ++nit ) + { + os << ' ' << (*nit); + } + } +} + +// NOT DOCUMENTED... +template<class Dimen, class Vb, class Fcb> +std::istream & +Triangulation_data_structure<Dimen, Vb, Fcb> +::read_full_cells(std::istream & is, const std::vector<Vertex_handle> & 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_cell_handle> 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<class Dimen, class Vb, class Fcb> +std::ostream & +Triangulation_data_structure<Dimen, Vb, Fcb> +::write_full_cells(std::ostream & os, std::map<Vertex_const_handle, int> & index_of_vertex) const +{ + std::map<Full_cell_const_handle, int> 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<class Dimen, class Vb, class Fcb> +std::istream & +operator>>(std::istream & is, Triangulation_data_structure<Dimen, Vb, Fcb> & 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<Dimen, Vb, Fcb> 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<Vertex_handle> 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<class Dimen, class Vb, class Fcb> +std::ostream & +operator<<(std::ostream & os, const Triangulation_data_structure<Dimen, Vb, Fcb> & 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<Dimen, Vb, Fcb> 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<Vertex_handle, int> 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/src/common/include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h b/src/common/include/gudhi_patches/CGAL/Triangulation_ds_full_cell.h new file mode 100644 index 00000000..541a6a85 --- /dev/null +++ b/src/common/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 <CGAL/TDS_full_cell_default_storage_policy.h> +#include <CGAL/TDS_full_cell_mirror_storage_policy.h> +#include <CGAL/internal/Triangulation/Dummy_TDS.h> +#include <CGAL/Dimension.h> +#include <CGAL/Default.h> +#include <CGAL/array.h> + +namespace CGAL { + +template< class TDS = void, typename FullCellStoragePolicy = Default > +class Triangulation_ds_full_cell +{ + typedef typename Default::Get<FullCellStoragePolicy, TDS_full_cell_default_storage_policy>::type + Storage_policy; + typedef Triangulation_ds_full_cell<TDS> 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<TDS2, FullCellStoragePolicy> 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<int>(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<TDS,SSP> &) /* 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<TDS,SSP> &) /* 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<void, StoragePolicy> +{ +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 <typename TDS2> + struct Rebind_TDS + { + typedef Triangulation_ds_full_cell<TDS2, StoragePolicy> 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/src/common/include/gudhi_patches/CGAL/Triangulation_ds_vertex.h b/src/common/include/gudhi_patches/CGAL/Triangulation_ds_vertex.h new file mode 100644 index 00000000..381b97e1 --- /dev/null +++ b/src/common/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 <CGAL/Compact_container.h> +#include <CGAL/internal/Triangulation/Dummy_TDS.h> + +namespace CGAL { + +/* The template parameter TDS must be a model of the concept + * 'TriangulationDataStructure' that stores vertices of type + * 'Triangulation_ds_vertex<TDS>' + */ +template< class TDS = void > +class Triangulation_ds_vertex +{ + typedef Triangulation_ds_vertex<TDS> Self; + +public: + typedef TDS Triangulation_data_structure; + typedef typename TDS::Full_cell_handle Full_cell_handle; /* Concept */ + + template <typename TDS2> + struct Rebind_TDS /* Concept */ + { + typedef Triangulation_ds_vertex<TDS2> 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<TDS> &) /* Concept */ +{ + /*if( is_ascii(is) ) + {} + else {}*/ + return is; +} + +template< class TDS > +std::ostream & +operator<<(std::ostream & os, const Triangulation_ds_vertex<TDS> &) /* Concept */ +{ + /*if( is_ascii(os) ) + { + os << '\n'; + } + else {}*/ + return os; +} + +// Special case: specialization when template parameter is void. + +template<> +class Triangulation_ds_vertex<void> +{ +public: + typedef internal::Triangulation::Dummy_TDS Triangulation_data_structure; + typedef Triangulation_data_structure::Full_cell_handle Full_cell_handle; /* Concept */ + template <typename TDS2> + struct Rebind_TDS /* Concept */ + { + typedef Triangulation_ds_vertex<TDS2> Other; + }; +}; + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_DS_VERTEX_H diff --git a/src/common/include/gudhi_patches/CGAL/Triangulation_face.h b/src/common/include/gudhi_patches/CGAL/Triangulation_face.h new file mode 100644 index 00000000..bc9c1781 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <CGAL/internal/Static_or_dynamic_array.h> + +namespace CGAL { + +template< typename TDS > +class Triangulation_face +{ + typedef typename internal::Dimen_plus_one<typename TDS::Maximal_dimension>::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<int, Dimen_plus> 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/src/common/include/gudhi_patches/CGAL/Triangulation_full_cell.h b/src/common/include/gudhi_patches/CGAL/Triangulation_full_cell.h new file mode 100644 index 00000000..a0c5246f --- /dev/null +++ b/src/common/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 <CGAL/Triangulation_ds_full_cell.h> +#include <CGAL/internal/Triangulation/utilities.h> +#include <CGAL/Iterator_project.h> +#include <CGAL/Default.h> + +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<TDSFullCell, Triangulation_ds_full_cell<> >::type +{ + // The default type for TDSFullCell is Triangulation_ds_full_cell<> : + typedef typename Default::Get<TDSFullCell, Triangulation_ds_full_cell<> >::type + Base; + typedef Triangulation_full_cell<TriangulationTraits, Data_, TDSFullCell> 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<TDS2>::Other TDSFullCell2; + typedef Triangulation_full_cell<TriangulationTraits, Data_, TDSFullCell2> 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<Vertex_handle, Point> + > 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<TDS, Data, SSP> & 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<TDS, Data, SSP> & s) +{ + /*if( is_ascii(I) ) + {} + else {}*/ + I >> s.data(); + return I; +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_SIMPLEX_H diff --git a/src/common/include/gudhi_patches/CGAL/Triangulation_vertex.h b/src/common/include/gudhi_patches/CGAL/Triangulation_vertex.h new file mode 100644 index 00000000..f364717f --- /dev/null +++ b/src/common/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 <CGAL/Triangulation_ds_vertex.h> +#include <CGAL/Default.h> + +namespace CGAL { + +struct No_vertex_data {}; + +template< class TriangulationTraits, typename Data_ = No_vertex_data, class TDSVertex = Default > +class Triangulation_vertex : public Default::Get<TDSVertex, Triangulation_ds_vertex<> >::type +{ + // The default type for TDSVertex is Triangulation_ds_vertex<> : + typedef typename Default::Get<TDSVertex, Triangulation_ds_vertex<> >::type + Base; + typedef Triangulation_vertex<TriangulationTraits, Data_, TDSVertex> 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 <typename TDS2> + struct Rebind_TDS + { + typedef typename Base::template Rebind_TDS<TDS2>::Other TDSVertex2; + typedef Triangulation_vertex<TriangulationTraits, Data_, TDSVertex2> 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<A, Data, B> & v) +{ + is >> v.point(); + return (is >> v.data()); +} + +template< class A, typename Data, class B > +std::ostream & +operator<<(std::ostream & os, const Triangulation_vertex<A, Data, B> & v) +{ + os << v.point(); + os << v.data(); + return os; +} + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_VERTEX_H diff --git a/src/common/include/gudhi_patches/CGAL/argument_swaps.h b/src/common/include/gudhi_patches/CGAL/argument_swaps.h new file mode 100644 index 00000000..aa16f29b --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#include <utility> + +#ifndef CGAL_CXX11 +#include <boost/preprocessor/repetition.hpp> +#include <boost/utility/result_of.hpp> +#endif + +namespace CGAL { + +#ifdef CGAL_CXX11 + +namespace internal { + +template<int,class...> struct Apply_to_last_then_rest_; + +template<int d,class F,class T,class... U> +struct Apply_to_last_then_rest_<d,F,T,U...> { + typedef typename Apply_to_last_then_rest_<d-1,F,U...,T>::result_type result_type; + inline result_type operator()(F&&f,T&&t,U&&...u)const{ + return Apply_to_last_then_rest_<d-1,F,U...,T>()( + std::forward<F>(f), + std::forward<U>(u)..., + std::forward<T>(t)); + } +}; + +template<class F,class T,class... U> +struct Apply_to_last_then_rest_<0,F,T,U...> { + typedef decltype(std::declval<F>()(std::declval<T>(), std::declval<U>()...)) result_type; + inline result_type operator()(F&&f,T&&t,U&&...u)const{ + return std::forward<F>(f)(std::forward<T>(t), std::forward<U>(u)...); + } +}; + +} // namespace internal + + +struct Apply_to_last_then_rest { + template<class F,class T,class...U> inline + typename internal::Apply_to_last_then_rest_<sizeof...(U),F,T,U...>::result_type + operator()(F&&f,T&&t,U&&...u)const{ + return internal::Apply_to_last_then_rest_<sizeof...(U),F,T,U...>()( + std::forward<F>(f), + std::forward<T>(t), + std::forward<U>(u)...); + } +}; + +#else // CGAL_CXX11 + +struct Apply_to_last_then_rest { +#define CGAL_CODE(Z,N,_) template<class F,class T,BOOST_PP_ENUM_PARAMS(N,class T)> \ + typename boost::result_of<F(T,BOOST_PP_ENUM_PARAMS(N,T))>::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/src/common/include/gudhi_patches/CGAL/determinant_of_vectors.h b/src/common/include/gudhi_patches/CGAL/determinant_of_vectors.h new file mode 100644 index 00000000..e1bad64e --- /dev/null +++ b/src/common/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 <CGAL/determinant.h> +#include <CGAL/predicates/sign_of_determinant.h> + +namespace CGAL { + // TODO: determine whether it is better to pass them by lines or columns. + + template <class NT, class Vector> inline + NT determinant_of_vectors(Vector const&a, Vector const&b){ + return determinant<NT>(a[0],a[1],b[0],b[1]); + } + template <class NT, class Vector> inline + typename Sgn<NT>::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b){ + return sign_of_determinant<NT>(a[0],a[1],b[0],b[1]); + } + + template <class NT, class Vector> + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c){ + return determinant<NT>(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2]); + } + template <class NT, class Vector> + typename Sgn<NT>::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c){ + return sign_of_determinant<NT>(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2]); + } + + template <class NT, class Vector> + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return determinant<NT>( + 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 <class NT, class Vector> + typename Sgn<NT>::result_type + sign_of_determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d){ + return sign_of_determinant<NT>( + 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 <class NT, class Vector> + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e){ + return determinant<NT>( + 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 <class NT, class Vector> + typename Sgn<NT>::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<NT>( + 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 <class NT, class Vector> + NT determinant_of_vectors(Vector const&a, Vector const&b, + Vector const&c, Vector const&d, Vector const&e, Vector const&f){ + return determinant<NT>( + 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 <class NT, class Vector> + typename Sgn<NT>::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<NT>( + 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/src/common/include/gudhi_patches/CGAL/internal/Combination_enumerator.h b/src/common/include/gudhi_patches/CGAL/internal/Combination_enumerator.h new file mode 100644 index 00000000..f411e827 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> +#include <vector> + +namespace CGAL { + +namespace internal { + +class Combination_enumerator +{ + // types and member data + typedef std::vector<int> 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/src/common/include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h b/src/common/include/gudhi_patches/CGAL/internal/Static_or_dynamic_array.h new file mode 100644 index 00000000..ee6195d9 --- /dev/null +++ b/src/common/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 <CGAL/Compact_container.h> +#include <CGAL/Dimension.h> +#include <CGAL/array.h> +#include <vector> + +namespace CGAL { + +namespace internal { + +// Utility for adding one to an Dimension_tag: + +template<typename D> +struct Dimen_plus_one; + +template<> +struct Dimen_plus_one<Dynamic_dimension_tag> +{ + typedef Dynamic_dimension_tag type; +}; + +template<int D> +struct Dimen_plus_one<Dimension_tag<D> > +{ + typedef Dimension_tag<D+1> type; +}; + +// A SMALL CONTAINER UTILITY FOR DYNAMIC/STATIC MEMORY MANAGEMENT + +// stores an array of static or dynamic size, depending on template parameter <B>. + +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<Containee, D> +{ + typedef array<Containee, D> 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<Containee> +{ + typedef std::vector<Containee> 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<Containee> +{ + typedef std::vector<Containee> 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/src/common/include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h b/src/common/include/gudhi_patches/CGAL/internal/Triangulation/Dummy_TDS.h new file mode 100644 index 00000000..b3a0ec98 --- /dev/null +++ b/src/common/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/src/common/include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h b/src/common/include/gudhi_patches/CGAL/internal/Triangulation/Triangulation_ds_iterators.h new file mode 100644 index 00000000..7e360026 --- /dev/null +++ b/src/common/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<TDS> 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/src/common/include/gudhi_patches/CGAL/internal/Triangulation/utilities.h b/src/common/include/gudhi_patches/CGAL/internal/Triangulation/utilities.h new file mode 100644 index 00000000..a1ffc775 --- /dev/null +++ b/src/common/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 <CGAL/basic.h> + +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/src/common/include/gudhi_patches/CGAL/iterator_from_indices.h b/src/common/include/gudhi_patches/CGAL/iterator_from_indices.h new file mode 100644 index 00000000..110bb4be --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#include <boost/iterator/iterator_facade.hpp> +namespace CGAL { +template <class Ref_> +struct Default_coordinate_access { + typedef Ref_ result_type; + template<class T> Ref_ operator()(T const& t, std::ptrdiff_t i)const{ + return t[i]; + } +}; + +//TODO: default type for Value_: typename same_cv<Container_,typename remove_cv<Container_>::type::value_type>::type +template <class Container_, class Value_, class Ref_= +#ifdef CGAL_CXX11 + decltype(std::declval<Container_>()[0]) +#else + Value_& +#endif + , class Coord_access = Default_coordinate_access<Ref_> + > +class Iterator_from_indices +: public boost::iterator_facade<Iterator_from_indices<Container_,Value_,Ref_,Coord_access>, + 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<class T> + 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/src/common/include/gudhi_patches/CGAL/transforming_iterator.h b/src/common/include/gudhi_patches/CGAL/transforming_iterator.h new file mode 100644 index 00000000..15ea19a5 --- /dev/null +++ b/src/common/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 <boost/iterator/iterator_adaptor.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/type_traits/is_empty.hpp> +#include <boost/type_traits/is_reference.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <CGAL/Default.h> +#include <utility> + +// Inspired by the boost version, but more compact and +// without any iterator_category games. + +namespace CGAL { +namespace internal { + +// non-empty case +template<class T,bool=boost::is_empty<T>::value> struct Functor_as_base { + Functor_as_base(){} + Functor_as_base(T const& t):f(t){} + //template<class T2> Functor_as_base(Functor_as_base<T2> const&g):f(g.functor()){} + T const& functor()const{return f;} + T & functor() {return f;} + private: + T f; +}; + +// empty case +template<class T> struct Functor_as_base<T,true> : public T { + Functor_as_base(){} + Functor_as_base(T const& t):T(t){} + //template<class T2> Functor_as_base(Functor_as_base<T2> const&g):T(g.functor()){} + T const& functor()const{return *this;} + T & functor() {return *this;} +}; + +template <typename Derived, typename F, typename Iter, typename Ref, typename Val> +class transforming_iterator_helper +{ + typedef std::iterator_traits<Iter> Iter_traits; + typedef typename Iter_traits::reference Iter_ref; + typedef typename Default::Get<Ref, +#ifdef CGAL_CXX11 + decltype(std::declval<F>()(std::declval<Iter_ref>())) +#else + typename boost::result_of<F(typename Iter_traits::value_type)>::type + // should be reference instead of value_type +#endif + >::type reference_; + + typedef typename Default::Get<Val,typename boost::remove_cv<typename boost::remove_reference<reference_>::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_reference<Iter_ref>, + boost::is_integral<Iter_ref> >, + reference_, value_type>::type reference; + + public: + typedef boost::iterator_adaptor< + Derived, + Iter, + value_type, + typename Iter_traits::iterator_category, + reference + > type; +}; +} + +template <typename F, typename Iter, typename Ref=Default, typename Val=Default> +class transforming_iterator +: public internal::transforming_iterator_helper<transforming_iterator<F,Iter,Ref,Val>,F,Iter,Ref,Val>::type, +private internal::Functor_as_base<F> +{ + friend class boost::iterator_core_access; + typedef typename internal::transforming_iterator_helper<transforming_iterator,F,Iter,Ref,Val>::type Base; + typedef internal::Functor_as_base<F> 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<class F2,class I2,class R2,class V2> + transforming_iterator( + transforming_iterator<F2,I2,R2,V2> const&i, + typename boost::enable_if_convertible<I2, Iter>::type* = 0, + typename boost::enable_if_convertible<F2, F>::type* = 0) + : Base(i.base()),Functor_base(i.functor()) {} + +}; + +template <typename F, typename Iter> inline +transforming_iterator<F,Iter> make_transforming_iterator(Iter i, F const&f=F()) { + return transforming_iterator<F,Iter>(i,f); +} + +} + +#endif // CGAL_TRANSFORMING_ITERATOR_H diff --git a/src/common/include/gudhi_patches/CGAL/transforming_pair_iterator.h b/src/common/include/gudhi_patches/CGAL/transforming_pair_iterator.h new file mode 100644 index 00000000..48dac132 --- /dev/null +++ b/src/common/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 <CGAL/transforming_iterator.h> +#include <CGAL/assertions.h> +#include <boost/type_traits/is_convertible.hpp> + + + + +namespace CGAL { +namespace internal { +template <class Cat1, class Cat2, bool=boost::is_convertible<Cat1,Cat2>::value> +struct Min_category { + CGAL_static_assertion((boost::is_convertible<Cat2,Cat1>::value)); + typedef Cat1 type; +}; + +template <class Cat1, class Cat2> +struct Min_category<Cat1,Cat2,true> { + typedef Cat2 type; +}; + + +template <typename Derived, typename F, typename It1, typename It2, typename Ref, typename Val> +class transforming_pair_iterator_helper +{ + typedef typename Min_category< + typename std::iterator_traits<It1>::iterator_category, + typename std::iterator_traits<It1>::iterator_category> + ::type iterator_category; + + typedef typename Default::Get<Ref, +#ifdef CGAL_CXX11 + decltype(std::declval<F>()(std::declval<typename std::iterator_traits<It1>::reference>(),std::declval<typename std::iterator_traits<It2>::reference>())) +#else + typename boost::result_of<F(typename std::iterator_traits<It1>::value_type,typename std::iterator_traits<It2>::value_type)>::type + // should be reference instead of value_type +#endif + >::type reference; + + typedef typename Default::Get<Val,typename boost::remove_cv<typename boost::remove_reference<reference>::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 <typename F, typename It1, typename It2, typename Ref=Default, typename Val=Default> +class transforming_pair_iterator +: public internal::transforming_pair_iterator_helper<transforming_pair_iterator<F,It1,It2,Ref,Val>,F,It1,It2,Ref,Val>::type, +private internal::Functor_as_base<F> +{ + It1 iter1; It2 iter2; + friend class boost::iterator_core_access; + typedef typename internal::transforming_pair_iterator_helper<transforming_pair_iterator,F,It1,It2,Ref,Val>::type Base; + typedef internal::Functor_as_base<F> 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<class F2,class J1,class J2,class R2,class V2> + transforming_pair_iterator( + transforming_pair_iterator<F2,J1,J2,R2,V2> const&i, + typename boost::enable_if_convertible<J1, It1>::type* = 0, + typename boost::enable_if_convertible<J2, It2>::type* = 0, + typename boost::enable_if_convertible<F2, F>::type* = 0) + : Functor_base(i.functor()),iter1(i.iter1),iter2(i.iter2) {} + +}; + +template <typename F, typename It1, typename It2> inline +transforming_pair_iterator<F,It1,It2> make_transforming_pair_iterator(It1 i1, It2 i2, F const&f=F()) { + return transforming_pair_iterator<F,It1,It2>(i1,i2,f); +} + +} + +#endif // CGAL_TRANSFORMING_PAIR_ITERATOR_H diff --git a/src/common/include/gudhi_patches/CGAL/typeset.h b/src/common/include/gudhi_patches/CGAL/typeset.h new file mode 100644 index 00000000..d4e24281 --- /dev/null +++ b/src/common/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 <CGAL/config.h> +#ifdef CGAL_CXX11 +#include <type_traits> +#else +#include <boost/type_traits.hpp> +#endif + +// Sometimes using tuple just to list types is overkill (takes forever to +// instantiate). + +namespace CGAL { +#ifdef CGAL_CXX11 + template<class...> struct typeset; + template<class H,class...U> struct typeset<H,U...> { + typedef H head; + typedef typeset<U...> tail; + typedef typeset type; + template<class X> using contains = typename + std::conditional< + std::is_same<H,X>::value, + std::true_type, + typename tail::template contains<X> + >::type; + template<class X> using add = typename + std::conditional< + contains<X>::value, + typeset<H,U...>, + typeset<H,U...,X> + >::type; + }; + template<> struct typeset<> { + typedef typeset type; + template<class X> using contains = std::false_type; + template<class X> using add = typeset<X>; + }; +#else + template<class,class> struct typeset; + template<class H=void, class T=typename + boost::mpl::if_<boost::is_same<H,void>, void, typeset<void, void> >::type > + struct typeset { + typedef typeset type; + typedef H head; + typedef T tail; + template<class X> struct contains : + boost::mpl::if_<boost::is_same<H,X>,boost::true_type,typename tail::template contains<X> >::type + {}; + template<class X,class=void> struct add; + //boost::mpl::if_<boost::is_same<H,X>,typeset,typeset<X,typeset> >::type + }; + template<> struct typeset<> { + typedef typeset type; + template<class X> struct contains : boost::false_type {}; + template<class X> struct add : CGAL::typeset<X> {}; + }; + + template<class H,class T> + template<class X,class> + struct typeset<H,T>::add : typeset<H,typename T::template add<X>::type> {}; + template<class H,class T> + template<class V> + struct typeset<H,T>::add<H,V> : typeset<H,T> {}; +#endif + + template<class T1, class T2> struct typeset_union_ : + typeset_union_<typename T1::template add<typename T2::head>::type, typename T2::tail> + {}; + template<class T> struct typeset_union_ <T, typeset<> > : T {}; + + template<class T1, class T2> + struct typeset_intersection_ { + typedef typename T1::head H; + typedef typename typeset_intersection_<typename T1::tail,T2>::type U; + typedef typename +#ifdef CGAL_CXX11 + std::conditional<T2::template contains<H>::value, +#else + boost::mpl::if_<typename T2::template contains<H>, +#endif + typename U::template add<H>::type, U>::type type; + }; + template<class T> + struct typeset_intersection_<typeset<>,T> : typeset<> {}; + +#ifdef CGAL_CXX11 + template<class T1, class T2> + using typeset_union = typename typeset_union_<T1,T2>::type; + template<class T1, class T2> + using typeset_intersection = typename typeset_intersection_<T1,T2>::type; +#else + template<class T1, class T2> + struct typeset_union : typeset_union_<T1,T2>::type {}; + template<class T1, class T2> + struct typeset_intersection : typeset_intersection_<T1,T2>::type {}; +#endif +} +#endif |