diff --git a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h index 9c3a6a9677c..b2d6e1cc840 100644 --- a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h +++ b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h @@ -566,6 +566,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, std::size_t number_of_labels = get(vertex_label_cost_map, *(vertices(input_graph).first)).size(); bool success; + bool full_loop = false; do { success = false; @@ -644,6 +645,8 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT cut_time += timer.time(); #endif + if (full_loop && flow >= min_cut) + continue; if(min_cut - flow <= flow * tolerance) { continue; @@ -656,18 +659,158 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, std::size_t vertex_i = get (vertex_index_map, vd); alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha); } - } - } while(success); + } + full_loop = true; + } while (success); #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT - CGAL_TRACE_STREAM << "vertex creation time: " << vertex_creation_time << - std::endl; - CGAL_TRACE_STREAM << "edge creation time: " << edge_creation_time << std::endl; - CGAL_TRACE_STREAM << "max flow algorithm time: " << cut_time << std::endl; + CGAL_TRACE_STREAM << "vertex creation time: " << vertex_creation_time << + std::endl; + CGAL_TRACE_STREAM << "edge creation time: " << edge_creation_time << std::endl; + CGAL_TRACE_STREAM << "max flow algorithm time: " << cut_time << std::endl; #endif - return min_cut; -} + return min_cut; + } + + + template + double min_cut(const InputGraph& input_graph, + EdgeCostMap edge_cost_map, + VertexLabelCostMap vertex_label_cost_map, + VertexLabelMap vertex_label_map, + const NamedParameters& np) + { + using parameters::choose_parameter; + using parameters::get_parameter; + + typedef boost::graph_traits GT; + typedef typename GT::edge_descriptor input_edge_descriptor; + typedef typename GT::vertex_descriptor input_vertex_descriptor; + + typedef typename GetInitializedVertexIndexMap::type VertexIndexMap; + VertexIndexMap vertex_index_map = CGAL::get_initialized_vertex_index_map(input_graph, np); + + typedef typename GetImplementationTag::type Impl_tag; + + // select implementation + typedef typename std::conditional + ::value, + Alpha_expansion_boost_adjacency_list_impl, + typename std::conditional + ::value, + Alpha_expansion_boost_compressed_sparse_row_impl, + Alpha_expansion_MaxFlow_impl>::type>::type + Alpha_expansion; + + typedef typename Alpha_expansion::Vertex_descriptor Vertex_descriptor; + + Alpha_expansion graph; + + double min_cut = (std::numeric_limits::max)(); + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + double vertex_creation_time, edge_creation_time, cut_time; + vertex_creation_time = edge_creation_time = cut_time = 0.0; +#endif + + std::vector inserted_vertices; + inserted_vertices.resize(num_vertices(input_graph)); + + graph.clear_graph(); + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + Timer timer; + timer.start(); +#endif + + // For E-Data + // add every input vertex as a vertex to the graph, put edges to source & sink vertices + for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph))) + { + std::size_t vertex_i = get(vertex_index_map, vd); + Vertex_descriptor new_vertex = graph.add_vertex(); + inserted_vertices[vertex_i] = new_vertex; + + double source_weight = get(vertex_label_cost_map, vd)[0]; + double sink_weight = get(vertex_label_cost_map, vd)[0]; + + graph.add_tweight(new_vertex, source_weight, sink_weight); + } +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + vertex_creation_time += timer.time(); + timer.reset(); +#endif + + // For E-Smooth + // add edge between every vertex, + for (input_edge_descriptor ed : CGAL::make_range(edges(input_graph))) + { + input_vertex_descriptor vd1 = source(ed, input_graph); + input_vertex_descriptor vd2 = target(ed, input_graph); + std::size_t idx1 = get(vertex_index_map, vd1); + std::size_t idx2 = get(vertex_index_map, vd2); + + double weight = get(edge_cost_map, ed); + + Vertex_descriptor v1 = inserted_vertices[idx1], + v2 = inserted_vertices[idx2]; + + graph.add_edge(v1, v2, weight, weight); + } + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + edge_creation_time += timer.time(); +#endif + + graph.init_vertices(); + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + timer.reset(); +#endif + + min_cut = graph.max_flow(); + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + cut_time += timer.time(); +#endif + +/* + //update labeling + for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph))) + { + std::size_t vertex_i = get(vertex_index_map, vd); + alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha); + }*/ + + graph.get_labels(vertex_index_map, vertex_label_map, inserted_vertices, CGAL::make_range(vertices(input_graph))); +/* + //update labeling + for (auto vd : vertices(input_graph)) { + std::size_t idx = get(vertex_index_map, vd); + int label = graph.get_label(inserted_vertices[idx]); + put(vertex_label_map, vd, label); + } + + for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph))) + { + std::size_t vertex_i = get(vertex_index_map, vd); + graph.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha); + }*/ + +#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT + CGAL_TRACE_STREAM << "vertex creation time: " << vertex_creation_time << + std::endl; + CGAL_TRACE_STREAM << "edge creation time: " << edge_creation_time << std::endl; + CGAL_TRACE_STREAM << "max flow algorithm time: " << cut_time << std::endl; +#endif + + return min_cut; + } /// \cond SKIP_IN_MANUAL @@ -701,6 +844,23 @@ double alpha_expansion_graphcut (const std::vector +double min_cut(const std::vector >& edges, + const std::vector& edge_costs, + const std::vector >& cost_matrix, + std::vector& labels, + const AlphaExpansionImplementationTag&) +{ + internal::Alpha_expansion_old_API_wrapper_graph graph(edges, edge_costs, cost_matrix, labels); + + return min_cut(graph, + graph.edge_cost_map(), + graph.vertex_label_cost_map(), + graph.vertex_label_map(), + CGAL::parameters::vertex_index_map(graph.vertex_index_map()). + implementation_tag(AlphaExpansionImplementationTag())); +} /// \endcond }//namespace CGAL diff --git a/Documentation/doc/CMakeLists.txt b/Documentation/doc/CMakeLists.txt index f9efeb99354..6325f7f980f 100644 --- a/Documentation/doc/CMakeLists.txt +++ b/Documentation/doc/CMakeLists.txt @@ -29,6 +29,18 @@ endif() find_package(Doxygen REQUIRED) find_package(Python3 REQUIRED COMPONENTS Interpreter) +if (NOT Python3_EXECUTABLE) + message(FATAL_ERROR "Cannot build the documentation without Python3!") + return() +endif() + +message(STATUS ${Python3_EXECUTABLE}) + +if(NOT DOXYGEN_FOUND) + message(WARNING "Cannot build the documentation without Doxygen!") + return() +endif() + #starting from cmake 3.9 the usage of DOXYGEN_EXECUTABLE is deprecated if(TARGET Doxygen::doxygen) get_property( diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index af93af92d6a..d1bfea9c010 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -103,6 +103,7 @@ \package_listing{Scale_space_reconstruction_3} \package_listing{Advancing_front_surface_reconstruction} \package_listing{Polygonal_surface_reconstruction} +\package_listing{Kinetic_space_partition} \package_listing{Optimal_transportation_reconstruction_2} \cgalPackageSection{PartGeometryProcessing,Geometry Processing} diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index f57c0ff3f43..eb90c3c0d86 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -151974,6 +151974,25 @@ pages = {179--189} organization={Wiley Online Library} } +@article{bauchet2020kinetic, +author = {Bauchet, Jean-Philippe and Lafarge, Florent}, +title = {Kinetic Shape Reconstruction}, +journal = "ACM Transactions on Graphics", +year = {2020}, +issue_date = {October 2020}, +publisher = {Association for Computing Machinery}, +address = {New York, NY, USA}, +volume = {39}, +number = {5}, +issn = {0730-0301}, +url = {https://doi.org/10.1145/3376918}, +doi = {10.1145/3376918}, +month = {jun}, +articleno = {156}, +numpages = {14}, +keywords = {polygonal surface mesh, Surface reconstruction, kinetic framework, surface approximation} +} + @article{levismooth, title={Smooth Rotation Enhanced As-Rigid-As-Possible Mesh Animation}, author={Levi, Zohar and Gotsman, Craig}, diff --git a/Installation/include/CGAL/license/Kinetic_space_partition.h b/Installation/include/CGAL/license/Kinetic_space_partition.h new file mode 100644 index 00000000000..c2d995017a0 --- /dev/null +++ b/Installation/include/CGAL/license/Kinetic_space_partition.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Andreas Fabri +// +// Warning: this file is generated, see include/CGAL/license/README.md + +#ifndef CGAL_LICENSE_KINETIC_SPACE_PARTITION_H +#define CGAL_LICENSE_KINETIC_SPACE_PARTITION_H + +#include +#include + +#ifdef CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE + +# if CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +# if defined(CGAL_LICENSE_WARNING) + + CGAL_pragma_warning("Your commercial license for CGAL does not cover " + "this release of the Kinetic Space Partition package.") +# endif + +# ifdef CGAL_LICENSE_ERROR +# error "Your commercial license for CGAL does not cover this release \ + of the Kinetic Space Partition package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +# endif // CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +#else // no CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE + +# if defined(CGAL_LICENSE_WARNING) + CGAL_pragma_warning("\nThe macro CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL Kinetic Space Partition package under " + "the terms of the GPLv3+.") +# endif // CGAL_LICENSE_WARNING + +# ifdef CGAL_LICENSE_ERROR +# error "The macro CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE is not defined.\ + You use the CGAL Kinetic Space Partition package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +#endif // no CGAL_KINETIC_SPACE_PARTITION_COMMERCIAL_LICENSE + +#endif // CGAL_LICENSE_KINETIC_SPACE_PARTITION_H diff --git a/Installation/include/CGAL/license/gpl_package_list.txt b/Installation/include/CGAL/license/gpl_package_list.txt index a66f7cdfea7..180d973f3a7 100644 --- a/Installation/include/CGAL/license/gpl_package_list.txt +++ b/Installation/include/CGAL/license/gpl_package_list.txt @@ -26,6 +26,7 @@ Inscribed_areas Inscribed Areas Interpolation 2D and Surface Function Interpolation Interval_skip_list Interval Skip List Jet_fitting_3 Estimation of Local Differential Properties of Point-Sampled Surfaces +Kinetic_space_partition Kinetic Space Partition Matrix_search Monotone and Sorted Matrix Search Mesh_2 2D Conforming Triangulations and Meshes Mesh_3 3D Mesh Generation diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCFaceAttribute.h b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCFaceAttribute.h new file mode 100644 index 00000000000..ebca32b6dec --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCFaceAttribute.h @@ -0,0 +1,39 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +/*! +\ingroup PkgKineticSpacePartitionConcepts +\cgalConcept + +The concept `KineticLCCFaceAttribute` refines `CellAttribute` to store additional information for each face related to its associated input polygon. + +\cgalHasModelsBegin +\cgalHasModelsBare{\link CGAL::Cell_attribute `Cell_attribute`\endlink} +\cgalHasModelsEnd + +\sa `CGAL::Kinetic_space_partition_3` +\sa `LinearCellComplexItems` +*/ + +struct KineticLCCFaceAttribute { +/// \name Access Members +/// @{ + /// 3D plane type compatible with `Kinetic_space_partition_3::Intersection_kernel` + typedef unspecified_type Plane_3; + /// Stores the index of the input polygon the provided that support plane of this face. Negative numbers correspond to the values defined in the enum `Kinetic_space_partition_3::Face_support`. + int input_polygon_index; + /// Support plane of the face derived from the corresponding input polygon or from octree nodes used for subdivision. + Plane_3 plane; + /// Does this face overlap with the corresponding input polygon. + bool part_of_initial_polygon; +/// @} +}; diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCItems.h b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCItems.h new file mode 100644 index 00000000000..469b78b026d --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCItems.h @@ -0,0 +1,40 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +/*! +\ingroup PkgKineticSpacePartitionConcepts +\cgalConcept + +The concept `KineticLCCItems` refines the concept of `LinearCellComplexItems` by adding 2-attributes and 3-attributes to store information from the kinetic partition. + +The first type in Attributes tuple must be a model of the `CellAttributeWithPoint` concept. +The third type in Attributes tuple must be a model of the `KineticLCCFaceAttribute` concept. +The fourth type in Attributes tuple must be a model of the `KineticLCCVolumeAttribute` concept. + +\cgalHasModelsBegin +\cgalHasModelsBare{`CGAL::Kinetic_space_partition_3::Linear_cell_complex_min_items`} +\cgalHasModelsEnd + +\sa `CGAL::Kinetic_space_partition_3` +\sa `KineticLCCFaceAttribute` +\sa `KineticLCCVolumeAttribute` +\sa `LinearCellComplexItems` +*/ + +struct KineticLCCItems { +/// \name Types +/// @{ + /// Using the index-based version of the `LinearCellComplex` concept. + typedef CGAL::Tag_true Use_index; + typedef std::uint32_t Index_type; +/// @} +}; diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCVolumeAttribute.h b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCVolumeAttribute.h new file mode 100644 index 00000000000..ea6c0c798d5 --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticLCCVolumeAttribute.h @@ -0,0 +1,37 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +/*! +\ingroup PkgKineticSpacePartitionConcepts +\cgalConcept + +The concept `KineticLCCVolumeAttribute` refines `CellAttribute` to store the barycenter and an id. + +\cgalHasModelsBegin +\cgalHasModelsBare{\link CGAL::Cell_attribute `Cell_attribute`\endlink} +\cgalHasModelsEnd + +\sa `CGAL::Kinetic_space_partition_3` +\sa `LinearCellComplexItems` +*/ + +struct KineticLCCVolumeAttribute { +/// \name Access Members +/// @{ + /// 3D point type compatible with `Kinetic_space_partition_3::Intersection_kernel` + typedef unspecified_type Point_3; + /// Contains the barycenter of the volume. + Point_3 barycenter; + /// 0-based volume id. + std::size_t volume_id; +/// @} +}; diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticPartitionTraits_3.h b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticPartitionTraits_3.h new file mode 100644 index 00000000000..a66dfbd778c --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Concepts/KineticPartitionTraits_3.h @@ -0,0 +1,253 @@ + /*! +\ingroup PkgKineticSpacePartitionConcepts +\cgalConcept + +A concept that describes the set of types required by the `CGAL::Kinetic_space_partition_3`. + +\cgalHasModelsBegin +\cgalHasModelsBare{All models of the concept `Kernel`} +\cgalHasModelsEnd + +\sa `CGAL::Kinetic_space_partition_3` +*/ +class KineticSpacePartitionTraits_3 { + +public: + +/// \name Types +/// @{ + + /// The 3D point type + typedef unspecified_type Point_3; + /// The 2D point type + typedef unspecified_type Point_2; + /// The 3D vector type + typedef unspecified_type Vector_3; + /// The 2D line type + typedef unspecified_type Line_2; + /// The 2D direction type + typedef unspecified_type Direction_2; + /// The plane type + typedef unspecified_type Plane_3; + /// The 2D vector type + typedef unspecified_type Vector_2; + /// The 2D segment type + typedef unspecified_type Segment_2; + /// The 3d tetrahedron type + typedef unspecified_type Tetrahedron_3; + /// The 3d transformation type + typedef unspecified_type Transform_3; + + /// The number type of the Cartesian coordinates + typedef unspecified_type FT; + + /*! + * Function object type that provides + * `Point_3 operator()(Origin p)` + * returning the point with 0, 0, 0 as Cartesian coordinates + * and `Point_3 operator()(FT x, FT y, FT z)` + * returning the point with `x`, `y` and `z` as Cartesian coordinates. + */ + typedef unspecified_type Construct_point_3; + + /*! + * Function object type that provides + * `Vector_3 operator()(Point_3 p1, Point_3 p2)` and + * `Vector_3 operator()(Origin p1, Point_3 p2)` + * returning the vector `p1p2`, `Vector_3 operator()(NULL_VECTOR)` returning + * the null vector, and `Vector_3 operator()(Line_3 l)` returning + * a vector having the same direction as `l` + */ + typedef unspecified_type Construct_vector_3; + + /*! + * Function object type that provides `Line_2 operator()(Point_2 p, Vector_2 d)` + * returning the line going through `p` in the direction of `d`. + */ + typedef unspecified_type Construct_line_2; + + /*! + * Function object type that provides + * `Point_2 operator()(Line_2 l, int i)` + * returning an arbitrary point on `l`. `i` is not used and can be of + * any value. + */ + typedef unspecified_type Construct_point_on_2; + + /*! + * Function object type that provides + * `Point_2 operator()(FT x, FT y)` + * returning the 2D point with `x` and `y` as Cartesian coordinates. + */ + typedef unspecified_type Construct_point_2; + + /*! + * Function object type that provides + * `Vector_2 operator()(Point_2 p1, Point_2 p2)` + * returning the vector `p1p2`, `Vector_2 operator()(NULL_VECTOR)` returning + * the null vector. + */ + typedef unspecified_type Construct_vector_2; + + /*! + * Function object type that provides + * `Tetrahedron_3 operator(Point_3 p, Point_3 q, Point_3 r, Point_3 s)` + * returning the tetrahedron with the points `p`, `q`, `r` and `s`. + */ + typedef unspecified_type ConstructTetrahedron_3; + + /*! + * Function object type that provides + * `FT operator()(Point_3 p)` and `FT operator()(Vector_3 v)` + * returning the `x` coordinate of a point and a vector respectively. + */ + typedef unspecified_type Compute_x_3; + + /*! + * Function object type that provides + * `FT operator()(Point_3 p)` and `FT operator()(Vector_3 v)` + * returning the `y` coordinate of a point and a vector respectively. + */ + typedef unspecified_type Compute_y_3; + + /*! + * Function object type that provides + * `FT operator()(Point_3 p)` and `FT operator()(Vector_3 v)` + * returning the `z` coordinate of a point and a vector respectively. + */ + typedef unspecified_type Compute_z_3; + + /*! + * Function object type that provides + * `FT operator()(Point_2 p)` and `FT operator()(Vector_2 v)` + * returning the `x` coordinate of a point and a vector respectively. + */ + typedef unspecified_type Compute_x_2; + + /*! + * Function object type that provides + * `FT operator()(Point_2 p)` and `FT operator()(Vector_2 v)` + * returning the `y` coordinate of a point and a vector respectively. + */ + typedef unspecified_type Compute_y_2; + + /*! + * Function object type that provides + * `FT operator()(Vector_2 v)` + * returning the squared length of `v`. + */ + typedef unspecified_type Compute_squared_length_2; + + /*! + * Function object type that provides + * `FT operator()(Vector_3 v1, Vector_3 v2)` + * returning the scalar product of `v1` and `v2`. + */ + typedef unspecified_type Compute_scalar_product_3; + + /*! + * Function object type that provides + * `Vector_3 operator() (Vector_3 v1, Vector_3 v2)` + * returning the `v1+v2`. + */ + typedef unspecified_type Construct_sum_of_vectors_3; + + /*! + * Function object type that provides + * `Vector_3 operator()(Plane_3 p)` + * returns a vector that is orthogonal to the plane `p` and directed to the positive side of `p`. + */ + typedef unspecified_type Construct_orthogonal_vector_3; + + /*! + * Function object type that provides + * `Plane_3 operator()(Point_3 p, Point_3 q, Point_3 r)` + * creates a plane passing through the points `p`, `q` and `r` and + * `Plane_3 operator()(Point_3 p, Vector_3 v)` + * introduces a plane that passes through point `p` and that is orthogonal to `V`. + */ + typedef unspecified_type Construct_plane_3; + + /*! + * Function object type that provides + * `Vector_3 operator()(Plane_3 h, Point_3 p) + * returns the orthogonal projection of `p` onto `h`. + */ + typedef unspecified_type Construct_projected_point_3; + + /*! + * Function object type that provides + * `bool operator()(Point_3 p, Point_3 q, Point_3 r)` + * returning true if the points `p`, `q`, and `r` are collinear and + * false otherwise. + */ + typedef unspecified_type Collinear_3; + + /*! + * Function object type that provides + * `Oriented_size operator()(Plane_3 h, Point_3 p)` + * returns `CGAL::ON_ORIENTED_BOUNDARY`, `CGAL::ON_NEGATIVE_SIDE`, or `CGAL::ON_POSITIVE_SIDE`, depending on the position of `p` relative to the oriented plane `h`. + */ + typedef unspecified_type Oriented_side_3; + +/// @} + +/// \name Access to Function Objects +/// @{ + + Construct_point_3 + construct_point_3_object(); + + Construct_vector_3 + construct_vector_3_object(); + + Construct_line_2 + construct_line_2_object(); + + Construct_point_on_3 + construct_point_on_3_object(); + + Construct_point_2 + construct_point_2_object(); + + Construct_vector_2 + construct_vector_2_object(); + + Construct_tetrahedron_3 + construct_tetrahedron_3_object(); + + Compute_x_3 + compute_x_3_object(); + + Compute_y_3 + compute_y_3_object(); + + Compute_z_3 + compute_z_3_object(); + + Compute_x_2 + compute_x_2_object(); + + Compute_y_2 + compute_y_2_object(); + + Compute_squared_length_2 + compute_squared_length_2_object(); + + Construct_sum_of_vectors_3 + construct_sum_of_vectors_3_object(); + + Construct_projected_point_3 + construct_projected_point_3_object(); + + Compute_scalar_product_3 + compute_scalar_product_3_object(); + + Collinear_3 + collinear_3_object(); + + Oriented_side_3 + oriented_side_3_object(); + +/// @} +}; diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Doxyfile.in b/Kinetic_space_partition/doc/Kinetic_space_partition/Doxyfile.in new file mode 100644 index 00000000000..96fddd29413 --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Doxyfile.in @@ -0,0 +1,7 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} + +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Kinetic Space Partition" +EXTRACT_ALL = NO +HIDE_UNDOC_CLASSES = YES +WARN_IF_UNDOCUMENTED = NO +PREDEFINED += DOXYGEN_RUNNING diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/Kinetic_space_partition.txt b/Kinetic_space_partition/doc/Kinetic_space_partition/Kinetic_space_partition.txt new file mode 100644 index 00000000000..50395b6caa4 --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/Kinetic_space_partition.txt @@ -0,0 +1,71 @@ +namespace CGAL { + +/*! + +\mainpage User Manual +\anchor Chapter_Kinetic_Space_Partition +\cgalAutoToc + +\authors Sven Oesau and Florent Lafarge + +\section Ksp_introduction Introduction + +This \cgal component implements the kinetic space partition proposed by Bauchet et. al \cgalCite{bauchet2020kinetic}. It takes as input a set of non-coplanar convex polygons and partitions the bounding box of the input into polyhedra, where each polyhedron and its facets are convex. Each facet of the partition is part of the input polygons or an extension of them. + +The kinetic partition homogeneously expands each input polygon along its support plane until collisions occur between them. At each collision, their expansion may stop, they may restrict the propagation along an intersection line between two support planes or they may continue beyond the intersection line. The polygons are split at the beginning of the kinetic simulation and at each collision along the intersection line to be intersection-free. + +Whether a polygon is expanded beyond an intersection with another polygon, depends on the user specified `k` parameter. Choosing `k = 1` will cause the expansion of polygons to locally stop at the first intersection with another polygon and choosing `k` equal to the number of input polygons will lead to a full expansion of each polygon to the bounding box. + +\section Ksp_algorithm Algorithm +The first step of the method creates a plane arrangement between the support planes of the input polygons. The computation of a plane arrangement has \cgalBigO{n^3}. To speed up the computation the input data can be decomposed into separate kinetic partitions using an octree. The decomposition limits the expansion of an input polygon to octree nodes it initially intersects. The usage of an octree significantly speeds up the creation of the kinetic partition. However, it adds facets to the partition which originate from the octree and do not belong to an input polygon. +The plane arrangement contains all points and lines of the intersections between the support planes and the bounding box. For each support plane, all intersections with the bounding box and other support planes are given by lines, edges and vertices of the arrangement. The kinetic partition created in the second step is a subset of faces of the arrangement depending on the `k` parameter. + +\cgalFigureBegin{Ksp_introductionfig,intersection_graph.png} +Plane arrangement.\n +Left: 4 convex polygons as input. Right: plane arrangement and bounding box together with input. +\cgalFigureEnd + +The kinetic partition for a chosen `k` is obtained by propagating each polygon within its support plane. As intersections with other polygons can only occur at the known edges in the plane arrangement, the 3D collision problem can be solved as separate 2D polygon edge collisions. + +\cgalFigureBegin{Ksp_algorithmfig,k_variation.png} +Impact of `k` parameter on partition.\n +Left: Arrangement with 4 input polygons. Right: three columns with propagated polygons on top and volumes of kinetic partition on bottom for `k` = 1, `k` = 2 and `k` = 3 from left to right with 5, 8 and 12 created volumes respectively. +\cgalFigureEnd + +\subsection Ksp_parameters Parameters + +The algorithm has five parameters: + +- `k`: unsigned int\n +The main parameter of this method is `k`, the maximum number of intersections that can occur for a polygon before its expansion stops. The initial intersections of the original input polygons are not considered. Thus increasing the `k` leads to a higher complexity of the partitioning, i.e., a higher number of facets and a higher number of volumes. For a certain `k` the partition can be considered to be complete and an increase in `k` will not further increase the complexity of the partition. A typical choice of `k` is in the range of 1 to 3. + +- `reorient_bbox`: boolean\n +The default bounding box of the partition is axis-aligned. Setting `reorient_bbox` to true aligns the x-axis of the bounding box with the direction of the largest variation in horizontal direction of the input data while maintaining the z-axis. + +- `bbox_dilation_ratio`: FT\n +By default the size bounding box of the input data is increased by 10% to avoid that input polygons are coplanar with the sides of the bounding box. + +- `max_octree_node_size`: unsigned int\n +A kinetic partition is split into 8 subpartitions using an octree if the number of intersecting polygons is larger than specified. The default value is 40 polygons. + +- `max_octree_depth`: unsigned int\n +Limits the maximum depth of the octree decomposition. A limitation is necessary as arbitrary dense polygon configurations exist, e.g., a star. The default value is set to 3. + +\section Ksp_result Result +The kinetic partition can be accessed as a `LinearCellComplex` via `CGAL::Kinetic_space_partition_3::get_linear_cell_complex()`. + +\subsection Ksp_examples Examples + +The following example reads a set of polygons from a file and creates a kinetic partition. Increasing the `k` parameter to 2 or 3 leads to a more detailed kinetic partition. + +\cgalExample{Kinetic_space_partition/kinetic_partition.cpp} + + +\section Ksp_history Design and Implementation History + +This package is an implementation of Bauchet et. al \cgalCite{bauchet2020kinetic} with an octree replacing the grid subdivision. +A proof of concept of the kinetic partition was developed by Simon Giraudot and Dmitry Anisimov. + +*/ + +} /* namespace CGAL */ diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/PackageDescription.txt b/Kinetic_space_partition/doc/Kinetic_space_partition/PackageDescription.txt new file mode 100644 index 00000000000..24fc0f33b6e --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/PackageDescription.txt @@ -0,0 +1,39 @@ +/*! +\defgroup PkgKineticSpacePartitionRef Kinetic Space Partition Reference + +\defgroup PkgKineticSpacePartitionConcepts Concepts +\ingroup PkgKineticSpacePartitionRef + +\addtogroup PkgKineticSpacePartitionRef +\cgalPkgDescriptionBegin{Kinetic Space Partition, PkgKineticSpacePartition} +\cgalPkgPicture{kinetic_logo.png} + +\cgalPkgSummaryBegin +\cgalPkgAuthors{Sven Oesau and Florent Lafarge} +\cgalPkgDesc{This package implements kinetic space partition. Based on a set of planar input shapes the bounding box of the input data is split into convex volumes. The complexity of the partition can be adjusted with a single parameter.} +\cgalPkgManuals{Chapter_Kinetic_Space_Partition, PkgKineticSpacePartitionRef} +\cgalPkgSummaryEnd + +\cgalPkgShortInfoBegin +\cgalPkgSince{6.0} +\cgalPkgDependsOn{\ref PkgSurfaceMesh, \ref PkgLinearCellComplex} +\cgalPkgBib{cgal:ol-kinetic} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgShortInfoEnd + +\cgalPkgDescriptionEnd + +\cgalClassifedRefPages + +\cgalCRPSection{Concepts} + +- `KineticSpacePartitionTraits_3` +- `KineticLCCItems` +- `KineticLCCFaceAttribute` +- `KineticLCCVolumeAttribute` + +\cgalCRPSection{Classes} + +- `CGAL::Kinetic_space_partition_3` + +*/ diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/dependencies b/Kinetic_space_partition/doc/Kinetic_space_partition/dependencies new file mode 100644 index 00000000000..d331e430188 --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/dependencies @@ -0,0 +1,9 @@ +Manual +Kernel_23 +BGL +Circulator +Linear_cell_complex +Combinatorial_map +Surface_mesh +Property_map +Polygon_mesh_processing \ No newline at end of file diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/examples.txt b/Kinetic_space_partition/doc/Kinetic_space_partition/examples.txt new file mode 100644 index 00000000000..86b3ba85913 --- /dev/null +++ b/Kinetic_space_partition/doc/Kinetic_space_partition/examples.txt @@ -0,0 +1,3 @@ +/*! +\example Kinetic_space_partition/kinetic_partition.cpp +*/ diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/fig/intersection_graph.png b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/intersection_graph.png new file mode 100644 index 00000000000..f011b1fad72 Binary files /dev/null and b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/intersection_graph.png differ diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/fig/k_variation.png b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/k_variation.png new file mode 100644 index 00000000000..e46eadf5e85 Binary files /dev/null and b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/k_variation.png differ diff --git a/Kinetic_space_partition/doc/Kinetic_space_partition/fig/kinetic_logo.png b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/kinetic_logo.png new file mode 100644 index 00000000000..c6e143644ce Binary files /dev/null and b/Kinetic_space_partition/doc/Kinetic_space_partition/fig/kinetic_logo.png differ diff --git a/Kinetic_space_partition/examples/Kinetic_space_partition/CMakeLists.txt b/Kinetic_space_partition/examples/Kinetic_space_partition/CMakeLists.txt new file mode 100644 index 00000000000..2e3f55c04c6 --- /dev/null +++ b/Kinetic_space_partition/examples/Kinetic_space_partition/CMakeLists.txt @@ -0,0 +1,24 @@ +# Created by the script cgal_create_CMakeLists. +# This is the CMake script for compiling a set of CGAL applications. + +cmake_minimum_required(VERSION 3.1...3.23) + +project(Kinetic_space_partition_Examples) + +find_package(CGAL REQUIRED) +include(CGAL_CreateSingleSourceCGALProgram) + +find_package(Eigen3 3.1.0 REQUIRED) +if(Eigen3_FOUND) + message(STATUS "Found Eigen") + include(CGAL_Eigen_support) + + set(targets kinetic_partition) + + foreach(target ${targets}) + create_single_source_cgal_program("${target}.cpp") + target_link_libraries(${target} PUBLIC CGAL::Eigen_support) + endforeach() +else() + message(ERROR "This program requires the Eigen library, and will not be compiled.") +endif() diff --git a/Kinetic_space_partition/examples/Kinetic_space_partition/data/test-4-rnd-polygons-4-6.off b/Kinetic_space_partition/examples/Kinetic_space_partition/data/test-4-rnd-polygons-4-6.off new file mode 100644 index 00000000000..eb5def17d8c --- /dev/null +++ b/Kinetic_space_partition/examples/Kinetic_space_partition/data/test-4-rnd-polygons-4-6.off @@ -0,0 +1,31 @@ +OFF +25 4 0 +0.42368054211531858133 0.18253980947404854773 0.43361217636176885293 +0.022479024642939653134 0.54906919604958193126 0.18056913227494222896 +0.2811647526241494166 0.52705548769951282573 0.022668645874355360104 +0.56065427807169632146 0.47592798567162025725 -0.10696848363655320213 +0.97118185417342761667 0.3697089496003267417 -0.25076552479989255851 +0.53714992649207637943 0.15247177832828684441 0.39492925062101502665 +0.47254430936410363184 -0.4706882612609787353 -0.2428207513377572957 +0.072755785530830729968 -0.01774935447864991328 -0.65160096675580014836 +-0.13624087681667856886 -0.19828919510256182157 -1 +0.050171309138895309188 -1 -1 +0.42195670307475763305 -1 -0.48389499638253974378 +0.49191328462142458466 -0.78271514577943301916 -0.31664816804310136344 +0.49305113818899937161 -0.56550106370623254293 -0.24495695687290242049 +-1 0.038516275072130623514 0.26001089527408571822 +-0.0052646635725682039419 0.32175247304120269121 -1 +0.79946300115531654384 1 -1 +-0.24605339821785221499 1 1 +-0.9554579135068776985 0.40209355388461098801 1 +-1 0.32023017788244112491 0.89940428108662362483 +0.71260765954572424796 -1 0.060430338155497906327 +0.93155151560319460202 -0.69967629334922809559 0.098656503647987087158 +1 -0.4563157020167216138 0.27001739515231759636 +1 0.14422055985065576622 0.91048995874330840294 +0.94048661719673254389 0.15625792052012871247 1 +-0.016691632221610047671 -1 1 +6 0 1 2 3 4 5 +7 6 7 8 9 10 11 12 +6 13 14 15 16 17 18 +6 19 20 21 22 23 24 diff --git a/Kinetic_space_partition/examples/Kinetic_space_partition/include/Parameters.h b/Kinetic_space_partition/examples/Kinetic_space_partition/include/Parameters.h new file mode 100644 index 00000000000..53682e3ce9a --- /dev/null +++ b/Kinetic_space_partition/examples/Kinetic_space_partition/include/Parameters.h @@ -0,0 +1,78 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSR_ALL_PARAMETERS_EXAMPLES_H +#define CGAL_KSR_ALL_PARAMETERS_EXAMPLES_H + +// STL includes. +#include + +namespace CGAL { +namespace KSR { + + template + struct All_parameters { + + // Path to the input data file. + std::string data; // required! + + // Boolean tags. + bool with_normals; // do we use normals + bool verbose;// verbose basic info + bool debug; // verbose more info + + // Shape detection / Shape regularization. + // See the corresponding CGAL packages. + std::size_t k_neighbors; + FT distance_threshold; + FT angle_threshold; + std::size_t min_region_size; + bool regularize; + + // Partitioning. + // See KSR/parameters.h + unsigned int k_intersections; + FT enlarge_bbox_ratio; + bool reorient; + + std::size_t max_octree_depth; + std::size_t max_octree_node_size; + + // Reconstruction. + FT graphcut_beta; // magic parameter between 0 and 1 + + // Constructor. + All_parameters() : + data(""), + // boolean tags + with_normals(true), + verbose(false), + debug(false), + // shape detection / shape regularization + k_neighbors(12), + min_region_size(100), + max_octree_node_size(40), + max_octree_depth(3), + // partition + k_intersections(1), + enlarge_bbox_ratio(FT(11) / FT(10)), + reorient(false), + // reconstruction + graphcut_beta(FT(1) / FT(2)) + { } + + }; + +} // KSR +} // CGAL + +#endif // CGAL_KSR_ALL_PARAMETERS_EXAMPLES_H diff --git a/Kinetic_space_partition/examples/Kinetic_space_partition/include/Terminal_parser.h b/Kinetic_space_partition/examples/Kinetic_space_partition/include/Terminal_parser.h new file mode 100644 index 00000000000..8ed99634931 --- /dev/null +++ b/Kinetic_space_partition/examples/Kinetic_space_partition/include/Terminal_parser.h @@ -0,0 +1,340 @@ +#ifndef CGAL_KSR_TERMINAL_PARSER_H +#define CGAL_KSR_TERMINAL_PARSER_H + +#if defined(WIN32) || defined(_WIN32) +#define _SR_ "\\" +#else +#define _SR_ "/" +#endif + +// STL includes. +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace KSR { + + template + class Terminal_parser { + + public: + using Input_parameters = std::unordered_map; + + Terminal_parser( + const int num_parameters, + const char** parameters, + const std::string path_to_save = "") : + m_path_to_save(path_to_save) { + + // Help. + show_help(num_parameters, parameters); + + // Handle all input parameters. + Input_parameters input_parameters; + set_input_parameters(num_parameters, parameters, input_parameters); + + // Set here all required parameters. + std::vector required(1); + required[0] = "-data"; + + // Set parameters. + set_parameters(input_parameters, required); + + // Set here all parameters that should not be saved. + std::vector exceptions(2); + exceptions[0] = "-data"; + exceptions[1] = "-params"; + + // Save parameters. + save_parameters_to_file(input_parameters, exceptions); + } + + inline Input_parameters& get_input_parameters() { + return m_parameters; + } + + inline const Input_parameters& get_input_parameters() const { + return m_parameters; + } + + template + void add_val_parameter( + const std::string parameter_name, + Scalar& variable_value) { + + if (!does_parameter_exist(parameter_name, m_parameters)) + return; + + const std::string parameter_value = m_parameters.at(parameter_name); + if (parameter_value != "default") + variable_value = static_cast(std::stod(parameter_value.c_str())); + std::cout << parameter_name << " : " << variable_value << std::endl; + } + + void add_str_parameter( + const std::string parameter_name, + std::string& variable_value) { + + if (!does_parameter_exist(parameter_name, m_parameters)) + return; + + const std::string parameter_value = m_parameters.at(parameter_name); + if (parameter_value != "default") + variable_value = parameter_value; + std::cout << parameter_name << " : " << variable_value << std::endl; + } + + void add_bool_parameter( + const std::string parameter_name, + bool& variable_value) { + + if (!does_parameter_exist(parameter_name, m_parameters)) + return; + + variable_value = true; + std::cout << parameter_name << " : " << (variable_value ? "true" : "false") << std::endl; + } + + private: + const std::string m_path_to_save; + Input_parameters m_parameters; + + // Help. + void show_help( + const int num_parameters, + const char** parameters) { + + if (!is_asked_for_help(num_parameters, parameters)) + return; + + print_help(); + exit(EXIT_SUCCESS); + } + + bool is_asked_for_help( + const int num_parameters, + const char** parameters) { + + for (int i = 0; i < num_parameters; ++i) + if (std::strcmp(parameters[i], "-help") == 0) + return true; + return false; + } + + void print_help() { + + std::cout << std::endl << "* HELP:" << std::endl; + + std::cout << std::endl << "* EXAMPLE:" << std::endl; + std::cout << + "your terminal name $ ." + << std::string(_SR_) << + "kinetic_reconstruction_example -data path_to_data" + << std::string(_SR_) << + "data_name.ply -other_param_name -other_param_value" + << std::endl << std::endl; + + std::cout << std::endl << "REQUIRED PARAMETERS:" << std::endl << std::endl; + + std::cout << + "parameter name: -data" << std::endl << + "parameter value: path_to_data" << std::string(_SR_) << "data_name.ply" << std::endl << + "description: path to the file with input data" << std::endl << std::endl; + + std::cout << std::endl << "OPTIONAL PARAMETERS:" << std::endl << std::endl; + + std::cout << + "parameter name: -silent" << std::endl << + "description: supress any intermediate output except for the final result" << std::endl << std::endl; + + std::cout << + "parameter name: -params" << std::endl << + "parameter value: path_to" << std::string(_SR_) << "parameters.ksr" << std::endl << + "description: load parameters from the file" << std::endl << std::endl; + } + + // Setting parameters. + void set_input_parameters( + const int num_parameters, + const char** parameters, + Input_parameters& input_parameters) { + + assert(num_parameters > 0); + for (int i = 1; i < num_parameters; ++i) { + + std::string str = static_cast(parameters[i]); + auto first_letter = str[0]; + + if (first_letter == '-') { + if (i + 1 < num_parameters) { + + str = static_cast(parameters[i + 1]); + first_letter = str[0]; + + if (first_letter != '-') + input_parameters[parameters[i]] = parameters[i + 1]; + else + input_parameters[parameters[i]] = "default"; + + } else input_parameters[parameters[i]] = "default"; + } + } + } + + void set_parameters( + Input_parameters& input_parameters, + const std::vector& required) { + + if (!are_required_parameters_set(input_parameters, required)) { + std::cerr << std::endl << + "ERROR: SEVERAL REQUIRED PARAMETERS ARE MISSING!" + << std::endl << std::endl; + exit(EXIT_FAILURE); + } + + if (parameters_should_be_loaded(input_parameters)) + load_parameters_from_file(input_parameters); + m_parameters = input_parameters; + } + + bool are_required_parameters_set( + const Input_parameters& input_parameters, + const std::vector& required) { + + bool are_all_set = true; + for (std::size_t i = 0; i < required.size(); ++i) + if (!is_required_parameter_set(required[i], input_parameters)) + are_all_set = false; + return are_all_set; + } + + bool is_required_parameter_set( + const std::string parameter_name, + const Input_parameters& input_parameters) { + + const bool is_set = does_parameter_exist(parameter_name, input_parameters) && + !does_parameter_have_default_value(parameter_name, input_parameters); + + if (!is_set) + std::cerr << std::endl << + parameter_name << " PARAMETER IS REQUIRED!" + << std::endl; + return is_set; + } + + bool does_parameter_exist( + const std::string parameter_name, + const Input_parameters& input_parameters) { + + for (Input_parameters::const_iterator parameter = input_parameters.begin(); + parameter != input_parameters.end(); ++parameter) + if ((*parameter).first == parameter_name) + return true; + return false; + } + + bool does_parameter_have_default_value( + const std::string parameter_name, + const Input_parameters& input_parameters) { + assert(does_parameter_exist(parameter_name, input_parameters)); + return input_parameters.at(parameter_name) == "default"; + } + + // Loading from a file. + bool parameters_should_be_loaded(const Input_parameters& input_parameters) { + if (does_parameter_exist("-params", input_parameters)) + return true; + return false; + } + + void load_parameters_from_file(Input_parameters& input_parameters) { + const std::string filePath = input_parameters.at("-params"); + if (filePath == "default") { + + std::cerr << std::endl << + "ERROR: PATH TO THE FILE WITH PARAMETERS IS NOT DEFINED!" + << std::endl << std::endl; + exit(EXIT_FAILURE); + } + + std::ifstream file(filePath.c_str(), std::ios_base::in); + if (!file) { + std::cerr << std::endl << + "ERROR: ERROR LOADING FILE WITH PARAMETERS!" + << std::endl << std::endl; + exit(EXIT_FAILURE); + } + + Input_parameters tmp_parameters; + while (!file.eof()) { + std::string parameter_name, parameter_value; + file >> parameter_name >> parameter_value; + + if (parameter_name == "" || parameter_value == "") + continue; + tmp_parameters[parameter_name] = parameter_value; + } + + for (Input_parameters::const_iterator pit = tmp_parameters.begin(); + pit != tmp_parameters.end(); ++pit) + input_parameters[(*pit).first] = (*pit).second; + file.close(); + } + + // Saving to a file. + void save_parameters_to_file( + const Input_parameters& input_parameters, + const std::vector& exceptions) { + + save_input_parameters(m_path_to_save, input_parameters, exceptions); + return; + } + + void save_input_parameters( + const std::string path_to_save, + const Input_parameters& input_parameters, + const std::vector& exceptions) { + + const std::string file_path = path_to_save + "parameters.ksr"; + save_parameters(file_path, input_parameters, exceptions); + std::cout << "* parameters are saved in: " << file_path << std::endl; + } + + void save_parameters( + const std::string file_path, + const Input_parameters& input_parameters, + const std::vector& exceptions) { + + std::ofstream file(file_path.c_str(), std::ios_base::out); + if (!file) { + std::cerr << std::endl << + "ERROR: SAVING FILE WITH THE NAME " << file_path + << std::endl << std::endl; + exit(EXIT_FAILURE); + } + + for (Input_parameters::const_iterator parameter = input_parameters.begin(); + parameter != input_parameters.end(); ++parameter) + if (parameter_should_be_saved((*parameter).first, exceptions)) + file << (*parameter).first << " " << (*parameter).second << std::endl; + file.close(); + } + + bool parameter_should_be_saved( + const std::string parameter_name, + const std::vector& exceptions) { + for (std::size_t i = 0; i < exceptions.size(); ++i) + if (exceptions[i] == parameter_name) + return false; + return true; + } + }; + +} // KSR +} // CGAL + +#endif // CGAL_KSR_TERMINAL_PARSER_H diff --git a/Kinetic_space_partition/examples/Kinetic_space_partition/kinetic_partition.cpp b/Kinetic_space_partition/examples/Kinetic_space_partition/kinetic_partition.cpp new file mode 100644 index 00000000000..2eaaf47bbe0 --- /dev/null +++ b/Kinetic_space_partition/examples/Kinetic_space_partition/kinetic_partition.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +using Kernel = EPICK; +using FT = typename Kernel::FT; +using Point_3 = typename Kernel::Point_3; + +using Surface_mesh = CGAL::Surface_mesh; +using KSP = CGAL::Kinetic_space_partition_3; +using Timer = CGAL::Real_timer; + +int main(int argc, char** argv) +{ + // Reading polygons from file + std::string input_filename = (argc > 1 ? argv[1] : "data/test-4-rnd-polygons-4-6.off"); + std::ifstream input_file(input_filename); + + std::vector input_vertices; + std::vector > input_faces; + + if (CGAL::IO::read_polygon_soup(input_filename, input_vertices, input_faces)) { + std::cout << "* reading the file: " << input_filename << "!" << std::endl; + input_file.close(); + } else { + std::cerr << "ERROR: can't read the file " << input_filename << "!" << std::endl; + return EXIT_FAILURE; + } + + std::cout << "--- INPUT STATS: \n* number of polygons: " << input_faces.size() << std::endl; + + // Parameters. + const unsigned int k = (argc > 2 ? std::atoi(argv[2]) : 1); + + // Initialization of Kinetic_space_partition_3 object. + // 'debug' set to true exports intermediate results into files in the working directory. + // The resulting volumes are exported into a volumes folder, if the folder already exists. + KSP ksp(CGAL::parameters::verbose(true).debug(true)); + + // Providing input polygons. + ksp.insert(input_vertices, input_faces); + + Timer timer; + timer.start(); + + // 'initialize' creates the intersection graph that is used for the partition. + ksp.initialize(CGAL::parameters::bbox_dilation_ratio(1.1).reorient_bbox(false)); + + // Creating the partition with allowing up to 'k' intersections for each kinetic polygon. + ksp.partition(k); + + timer.stop(); + const FT time = static_cast(timer.time()); + + // Access the kinetic partition via linear cell complex. + typedef CGAL::Linear_cell_complex_traits<3, EPECK> LCC_Traits; + CGAL::Linear_cell_complex_for_combinatorial_map<3, 3, LCC_Traits, typename KSP::Linear_cell_complex_min_items> lcc; + ksp.get_linear_cell_complex(lcc); + + std::vector cells = { 0, 2, 3 }, count; + count = lcc.count_cells(cells); + + std::cout << "For k = " << k << ":\n" << " vertices: " << count[0] << "\n faces: " << count[2] << "\n volumes: " << count[3] << std::endl; + + std::cout << "\n3D kinetic partition created in " << time << " seconds!" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Kinetic_space_partition/include/CGAL/KSP/debug.h b/Kinetic_space_partition/include/CGAL/KSP/debug.h new file mode 100644 index 00000000000..73fab72b648 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP/debug.h @@ -0,0 +1,1206 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_DEBUG_H +#define CGAL_KSP_DEBUG_H + +#include + +#if defined(WIN32) || defined(_WIN32) +#define _NL_ "\r\n" +#else +#define _NL_ "\n" +#endif + +// STL includes. +#include + +// CGAL includes. +#include +#include +#include +#include +#include +#include +#include + +// Internal includes. +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +const std::tuple +get_idx_color(std::size_t idx) { + + CGAL::Random rand(static_cast(idx)); + return std::make_tuple( + static_cast(rand.get_int(32, 192)), + static_cast(rand.get_int(32, 192)), + static_cast(rand.get_int(32, 192))); +} + +template +void dump_intersection_edges(const DS& data, const std::string tag = std::string()) { + + const std::string filename = (tag != std::string() ? tag + "-" : "") + "intersection-edges.polylines.txt"; + std::ofstream out(filename); + out.precision(20); + + for (const auto iedge : data.iedges()) { + out << "2 " << data.segment_3(iedge) << std::endl; + } + out.close(); +} + +template +void dump_segmented_edges(const DS& data, const std::string tag = std::string()) { + + std::vector out; + for (std::size_t i = 0; i < data.nb_intersection_lines(); ++i) { + const std::string filename = (tag != std::string() ? tag + "-" : "") + "intersection-line-" + std::to_string(i) + ".polylines.txt"; + out.push_back(new std::ofstream(filename)); + out.back()->precision(20); + } + + for (const auto iedge : data.iedges()) { + CGAL_assertion(data.line_idx(iedge) != std::size_t(-1)); + *(out[data.line_idx(iedge)]) << "2 " << data.segment_3(iedge) << std::endl; + } + + for (std::ofstream* o : out) { + delete o; + } +} + +template +void dump_constrained_edges(const DS& data, const std::string tag = std::string()) { + + const std::string filename = (tag != std::string() ? tag + "-" : "") + "constrained-edges.polylines.txt"; + std::ofstream out(filename); + out.precision(20); + + for (std::size_t i = 0; i < data.number_of_support_planes(); ++i) { + for (const auto pedge : data.pedges(i)) { + if (data.has_iedge(pedge)) { + out << "2 " << data.segment_3(pedge) << std::endl; + } + } + } + out.close(); +} + +template +void dump_2d_surface_mesh( + const DS& data, + const std::size_t support_plane_idx, + const std::string tag = std::string()) { + + using Point_3 = typename DS::Kernel::Point_3; + using Mesh = CGAL::Surface_mesh; + using Face_index = typename Mesh::Face_index; + using Vertex_index = typename Mesh::Vertex_index; + using Int_map = typename Mesh::template Property_map; + + Mesh mesh; + Int_map red = mesh.template add_property_map("red", 0).first; + Int_map green = mesh.template add_property_map("green", 0).first; + Int_map blue = mesh.template add_property_map("blue", 0).first; + + std::vector vertices; + std::vector map_vertices; + + map_vertices.clear(); + + for (const auto pvertex : data.pvertices(support_plane_idx)) { + if (map_vertices.size() <= pvertex.second) { + map_vertices.resize(pvertex.second + 1); + } + //pts.push_back(data.point_3(pvertex)); + map_vertices[pvertex.second] = mesh.add_vertex(data.point_3(pvertex)); + } + + for (const auto pface : data.pfaces(support_plane_idx)) { + vertices.clear(); + for (const auto pvertex : data.pvertices_of_pface(pface)) { + vertices.push_back(map_vertices[pvertex.second]); + } + + CGAL_assertion(vertices.size() >= 3); + const auto face = mesh.add_face(vertices); + if (face == Mesh::null_face()) { + std::cout << "could not dump mesh " << tag << std::endl; + return; + } + std::tie(red[face], green[face], blue[face]) = + get_idx_color((support_plane_idx + 1) * (pface.second + 1)); + } + + const std::string filename = (tag != std::string() ? tag + "-" : "") + "polygons.ply"; + std::ofstream out(filename); + out.precision(20); + CGAL::IO::write_PLY(out, mesh); + out.close(); +} + +template +void dump_polygons(const DS& data, const std::string tag = std::string()) { + + using Point_3 = typename DS::Point_3; + using Mesh = CGAL::Surface_mesh; + using Face_index = typename Mesh::Face_index; + using Vertex_index = typename Mesh::Vertex_index; + using Uchar_map = typename Mesh::template Property_map; + + Mesh mesh; + Uchar_map red = mesh.template add_property_map("red", 0).first; + Uchar_map green = mesh.template add_property_map("green", 0).first; + Uchar_map blue = mesh.template add_property_map("blue", 0).first; + + Mesh bbox_mesh; + Uchar_map bbox_red = bbox_mesh.template add_property_map("red", 0).first; + Uchar_map bbox_green = bbox_mesh.template add_property_map("green", 0).first; + Uchar_map bbox_blue = bbox_mesh.template add_property_map("blue", 0).first; + + std::vector vertices; + std::vector map_vertices; + + for (std::size_t i = 0; i < data.number_of_support_planes(); ++i) { + if (data.is_bbox_support_plane(i)) { + + map_vertices.clear(); + for (const auto pvertex : data.pvertices(i)) { + if (map_vertices.size() <= pvertex.second) { + map_vertices.resize(pvertex.second + 1); + } + map_vertices[pvertex.second] = bbox_mesh.add_vertex(data.point_3(pvertex)); + } + + for (const auto pface : data.pfaces(i)) { + vertices.clear(); + for (const auto pvertex : data.pvertices_of_pface(pface)) { + vertices.push_back(map_vertices[pvertex.second]); + } + + CGAL_assertion(vertices.size() >= 3); + const auto face = bbox_mesh.add_face(vertices); + CGAL_assertion(face != Mesh::null_face()); + std::tie(bbox_red[face], bbox_green[face], bbox_blue[face]) = + get_idx_color((i + 1) * (pface.second + 1)); + } + + } else { + + map_vertices.clear(); + for (const auto pvertex : data.pvertices(i)) { + if (map_vertices.size() <= pvertex.second) { + map_vertices.resize(pvertex.second + 1); + } + map_vertices[pvertex.second] = mesh.add_vertex(data.point_3(pvertex)); + } + + for (const auto pface : data.pfaces(i)) { + vertices.clear(); + for (const auto pvertex : data.pvertices_of_pface(pface)) { + vertices.push_back(map_vertices[pvertex.second]); + } + + CGAL_assertion(vertices.size() >= 3); + const auto face = mesh.add_face(vertices); + CGAL_assertion(face != Mesh::null_face()); + std::tie(red[face], green[face], blue[face]) = + get_idx_color(i * (pface.second + 1)); + } + } + } + + const std::string filename = (tag != std::string() ? tag + "-" : "") + "polygons.ply"; + std::ofstream out(filename); + out.precision(20); + CGAL::IO::write_PLY(out, mesh); + out.close(); + +#if false + + const std::string bbox_filename = (tag != std::string() ? tag + "-" : "") + "bbox-polygons.ply"; + std::ofstream bbox_out(bbox_filename); + bbox_out.precision(20); + CGAL::write_PLY(bbox_out, bbox_mesh); + bbox_out.close(); + +#endif +} + +template +void dump_polygon_borders(const DS& data, const std::string tag = std::string()) { + + const std::string filename = (tag != std::string() ? tag + "-" : "") + "polygon-borders.polylines.txt"; + std::ofstream out(filename); + out.precision(20); + for (std::size_t i = 6; i < data.number_of_support_planes(); ++i) { + for (const auto pedge : data.pedges(i)) { + out << "2 " << data.segment_3(pedge) << std::endl; + } + } + out.close(); +} + +template +void dump_event(const DS& data, const Event& ev, const std::string tag = std::string()) { + + if (ev.is_pvertex_to_pvertex()) { + + const std::string vfilename = (tag != std::string() ? tag + "-" : "") + "event-pvertex.xyz"; + std::ofstream vout(vfilename); + vout.precision(20); + vout << data.point_3(ev.pvertex()) << std::endl; + vout.close(); + + const std::string ofilename = (tag != std::string() ? tag + "-" : "") + "event-pother.xyz"; + std::ofstream oout(ofilename); + oout.precision(20); + oout << data.point_3(ev.pother()) << std::endl; + oout.close(); + + } else if (ev.is_pvertex_to_iedge()) { + + const std::string lfilename = (tag != std::string() ? tag + "-" : "") + "event-iedge.polylines.txt"; + std::ofstream lout(lfilename); + lout.precision(20); + lout << "2 " << data.segment_3(ev.iedge()) << std::endl; + lout.close(); + + const std::string vfilename = (tag != std::string() ? tag + "-" : "") + "event-pvertex.xyz"; + std::ofstream vout(vfilename); + vout.precision(20); + vout << data.point_3(ev.pvertex()); + vout.close(); + + } else if (ev.is_pvertex_to_ivertex()) { + + const std::string vfilename = (tag != std::string() ? tag + "-" : "") + "event-pvertex.xyz"; + std::ofstream vout(vfilename); + vout.precision(20); + vout << data.point_3(ev.pvertex()) << std::endl; + vout.close(); + + const std::string ofilename = (tag != std::string() ? tag + "-" : "") + "event-ivertex.xyz"; + std::ofstream oout(ofilename); + oout.precision(20); + oout << data.point_3(ev.ivertex()) << std::endl; + oout.close(); + } +} + +template +void dump(const DS& data, const std::string tag = std::string()) { + + dump_polygons(data, tag); + dump_intersection_edges(data, tag); +} + +template +class Saver { + +public: + using Traits = GeomTraits; + using FT = typename Traits::FT; + using Point_2 = typename Traits::Point_2; + using Point_3 = typename Traits::Point_3; + using Vector_3 = typename Traits::Vector_3; + using Segment_2 = typename Traits::Segment_2; + using Segment_3 = typename Traits::Segment_3; + + using Color = CGAL::IO::Color; + using Surface_mesh = CGAL::Surface_mesh; + using Random = CGAL::Random; + + Saver() : + m_path_prefix(""), + grey(Color(125, 125, 125)), + red(Color(125, 0, 0)) + { } + + void initialize(std::stringstream& stream) const { + stream.precision(20); + } + + void export_points_2( + const std::vector& points, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + for (const auto& point : points) + stream << point << " 0 " << std::endl; + save(stream, file_name + ".xyz"); + } + + void export_points_2( + const std::vector< std::vector >& regions, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + std::size_t num_points = 0; + for (const auto& region : regions) + num_points += region.size(); + add_ply_header_points(stream, num_points); + + for (std::size_t i = 0; i < regions.size(); ++i) { + const auto color = get_idx_color(i); + for (const auto& point : regions[i]) + stream << point << " 0 " << color << std::endl; + } + save(stream, file_name + ".ply"); + } + + void export_points_3( + const std::vector& points, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + for (const auto& point : points) + stream << point << std::endl; + save(stream, file_name + ".xyz"); + } + + void export_regions_3( + const std::vector& points, + const std::vector& normals, + const std::vector& region, + const std::string file_name) const { + + if (points.size() != normals.size()) { + std::cout << "export_regions_3: number of points and normals are not equal" << std::endl; + return; + } + + if (points.size() != region.size()) { + std::cout << "export_regions_3: number of points and region indices are not equal" << std::endl; + return; + } + + std::stringstream stream; + initialize(stream); + + add_ply_header_regions(stream, points.size()); + + for (std::size_t i = 0; i < points.size(); ++i) { + stream << points[i] << " " << normals[i] << " " << region[i] << std::endl; + } + save(stream, file_name); + } + + void export_points_3( + const std::vector& points, + const std::vector& normals, + const std::string file_name) const { + + if (points.size() != normals.size()) { + std::cout << "export_regions_3: number of points and normals are not equal" << std::endl; + return; + } + + std::stringstream stream; + initialize(stream); + + add_ply_header_normals(stream, points.size()); + + for (std::size_t i = 0; i < points.size(); ++i) { + stream << points[i] << " " << normals[i] << " " << std::endl; + } + save(stream, file_name); + } + + void export_points_3( + const std::vector& points, + const std::vector& normals, + const std::vector& colors, + const std::string file_name) const { + + if (points.size() != normals.size() && points.size() != colors.size()) { + std::cout << "export_regions_3: number of points and normals or colors are not equal" << std::endl; + return; + } + + std::stringstream stream; + initialize(stream); + + add_ply_header_normals_colors(stream, points.size()); + + for (std::size_t i = 0; i < points.size(); ++i) { + stream << points[i] << " " << normals[i] << " " << colors[i] << std::endl; + } + save(stream, file_name); + } + + void export_segments_2( + const std::vector& segments, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + for (const auto& segment : segments) + stream << "2 " << segment.source() << " 0 " << segment.target() << " 0 " << std::endl; + save(stream, file_name + ".polylines.txt"); + } + + void export_segments_3( + const std::vector& segments, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + for (const auto& segment : segments) + stream << "2 " << segment.source() << " " << segment.target() << std::endl; + save(stream, file_name + ".polylines.txt"); + } + + void export_polygon_soup_3( + const std::vector< std::vector >& polygons, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + std::size_t num_vertices = 0; + for (const auto& polygon : polygons) + num_vertices += polygon.size(); + std::size_t num_faces = polygons.size(); + add_ply_header_mesh(stream, num_vertices, num_faces); + + for (const auto& polygon : polygons) + for (const auto& p : polygon) + stream << p << std::endl; + + std::size_t i = 0, polygon_id = 0; + for (const auto& polygon : polygons) { + stream << polygon.size() << " "; + for (std::size_t j = 0; j < polygon.size(); ++j) + stream << i++ << " "; + stream << get_idx_color(polygon_id) << std::endl; + ++polygon_id; + } + save(stream, file_name + ".ply"); + } + + void export_polygon_soup_3( + const std::vector > >& polygons, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + std::size_t num_vertices = 0; + std::size_t num_faces = 0; + for (const auto& region : polygons) { + num_faces += region.size(); + for (const auto& polygon : region) + num_vertices += polygon.size(); + } + add_ply_header_mesh(stream, num_vertices, num_faces); + + for (const auto& region : polygons) + for(const auto& polygon : region) + for (const auto& p : polygon) + stream << p << std::endl; + + std::size_t i = 0, region_id = 0; + for (const auto& region : polygons) { + for (const auto& polygon : region) { + stream << polygon.size() << " "; + for (std::size_t j = 0; j < polygon.size(); ++j) + stream << i++ << " "; + stream << get_idx_color(region_id) << std::endl; + } + ++region_id; + } + save(stream, file_name + ".ply"); + } + + void export_indexed_triangles_3( + const std::vector& vertices, + const std::vector& tris, + const std::string file_name) const { + assert((tris.size() % 3) == 0); + + std::stringstream stream; + initialize(stream); + + add_ply_header_mesh_no_color(stream, vertices.size(), tris.size() / 3); + + for (const auto& v : vertices) + stream << v << std::endl; + + for (std::size_t i = 0; i < (tris.size() - 2); i += 3) + stream << "3 " << tris[i] << " " << tris[i + 1] << " " << tris[i + 2] << std::endl; + + save(stream, file_name + ".ply"); + } + + void export_indexed_polygons_3( + const std::vector& vertices, + const std::vector >& polys, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + add_ply_header_mesh_no_color(stream, vertices.size(), polys.size()); + + for (const auto& v : vertices) + stream << v << std::endl; + + for (const auto& poly : polys) { + stream << poly.size(); + for (std::size_t i = 0; i < poly.size(); i++) + stream << " " << poly[i]; + stream << std::endl; + } + + save(stream, file_name + ".ply"); + } + + void export_polygon_soup_3( + const std::vector< std::vector >& polygons, + const std::vector& colors, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + std::size_t num_vertices = 0; + for (const auto& polygon : polygons) + num_vertices += polygon.size(); + std::size_t num_faces = polygons.size(); + add_ply_header_mesh(stream, num_vertices, num_faces); + + for (const auto& polygon : polygons) + for (const auto& p : polygon) + stream << p << std::endl; + + std::size_t i = 0; + for (std::size_t k = 0; k < polygons.size(); ++k) { + stream << polygons[k].size() << " "; + for (std::size_t j = 0; j < polygons[k].size(); ++j) + stream << i++ << " "; + stream << colors[k] << std::endl; + } + save(stream, file_name + ".ply"); + } + + void export_bounding_box_3( + const std::array& bounding_box, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + Surface_mesh bbox; + CGAL_assertion(bounding_box.size() == 8); + CGAL::make_hexahedron( + bounding_box[0], bounding_box[1], bounding_box[2], bounding_box[3], + bounding_box[4], bounding_box[5], bounding_box[6], bounding_box[7], bbox); + stream << bbox; + save(stream, file_name + ".off"); + } + + void export_mesh_2( + const std::vector& vertices, + const std::vector< std::vector >& faces, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + add_ply_header_mesh(stream, vertices.size(), faces.size()); + for (const auto& vertex : vertices) + stream << vertex << " 0 " << std::endl; + + for (const auto& face : faces) { + stream << face.size(); + for (const std::size_t findex : face){ + stream << " " << findex; + } + stream << " " << grey << std::endl; + } + save(stream, file_name + ".ply"); + } + + void export_mesh_2( + const std::vector& vertices, + const std::vector< std::vector >& faces, + const std::vector& colors, + const std::string file_name) const { + + std::stringstream stream; + initialize(stream); + + add_ply_header_mesh(stream, vertices.size(), faces.size()); + for (const auto& vertex : vertices) + stream << vertex << " 0 " << std::endl; + + for (std::size_t k = 0; k < faces.size(); ++k) { + stream << faces[k].size(); + for (const std::size_t findex : faces[k]){ + stream << " " << findex; + } + stream << " " << colors[k] << std::endl; + } + save(stream, file_name + ".ply"); + } + + const Color get_idx_color(const std::size_t idx) const { + Random rand(static_cast(idx)); + const unsigned char r = rand.get_int(32, 192); + const unsigned char g = rand.get_int(32, 192); + const unsigned char b = rand.get_int(32, 192); + return Color(r, g, b); + } + +private: + const std::string m_path_prefix; + const Color grey, red; + + void save( + const std::stringstream& stream, + const std::string file_name) const { + + const std::string file_path = m_path_prefix + file_name; + std::ofstream file(file_path.c_str(), std::ios_base::out); + + if (!file) + std::cerr << std::endl << + "ERROR: WHILE SAVING FILE " << file_path + << "!" << std::endl << std::endl; + + file << stream.str(); + file.close(); + } + + void add_ply_header_points( + std::stringstream& stream, + const std::size_t size) const { + + stream << + "ply" + std::string(_NL_) + "" << + "format ascii 1.0" + std::string(_NL_) + "" << + "element vertex " << size << "" + std::string(_NL_) + "" << + "property double x" + std::string(_NL_) + "" << + "property double y" + std::string(_NL_) + "" << + "property double z" + std::string(_NL_) + "" << + "property uchar red" + std::string(_NL_) + "" << + "property uchar green" + std::string(_NL_) + "" << + "property uchar blue" + std::string(_NL_) + "" << + "property uchar alpha" + std::string(_NL_) + "" << + "end_header" + std::string(_NL_) + ""; + } + + void add_ply_header_normals( + std::stringstream& stream, + const std::size_t size) const { + + stream << + "ply" + std::string(_NL_) + "" << + "format ascii 1.0" + std::string(_NL_) + "" << + "element vertex " << size << "" + std::string(_NL_) + "" << + "property double x" + std::string(_NL_) + "" << + "property double y" + std::string(_NL_) + "" << + "property double z" + std::string(_NL_) + "" << + "property double nx" + std::string(_NL_) + "" << + "property double ny" + std::string(_NL_) + "" << + "property double nz" + std::string(_NL_) + "" << + "end_header" + std::string(_NL_) + ""; + } + + void add_ply_header_normals_colors( + std::stringstream& stream, + const std::size_t size) const { + + stream << + "ply" + std::string(_NL_) + "" << + "format ascii 1.0" + std::string(_NL_) + "" << + "element vertex " << size << "" + std::string(_NL_) + "" << + "property double x" + std::string(_NL_) + "" << + "property double y" + std::string(_NL_) + "" << + "property double z" + std::string(_NL_) + "" << + "property double nx" + std::string(_NL_) + "" << + "property double ny" + std::string(_NL_) + "" << + "property double nz" + std::string(_NL_) + "" << + "property uchar red" + std::string(_NL_) + "" << + "property uchar green" + std::string(_NL_) + "" << + "property uchar blue" + std::string(_NL_) + "" << + "property uchar alpha" + std::string(_NL_) + "" << + "end_header" + std::string(_NL_) + ""; + } + + void add_ply_header_regions( + std::stringstream& stream, + const std::size_t size) const { + + stream << + "ply" << std::endl << + "format ascii 1.0" << std::endl << + "element vertex " << size << std::endl << + "property double x" << std::endl << + "property double y" << std::endl << + "property double z" << std::endl << + "property double nx" << std::endl << + "property double ny" << std::endl << + "property double nz" << std::endl << + "property int region" << std::endl << + "end_header" << std::endl; + } + + void add_ply_header_mesh( + std::stringstream& stream, + const std::size_t num_vertices, + const std::size_t num_faces) const { + + stream << + "ply" + std::string(_NL_) + "" << + "format ascii 1.0" + std::string(_NL_) + "" << + "element vertex " << num_vertices << "" + std::string(_NL_) + "" << + "property double x" + std::string(_NL_) + "" << + "property double y" + std::string(_NL_) + "" << + "property double z" + std::string(_NL_) + "" << + "element face " << num_faces << "" + std::string(_NL_) + "" << + "property list uchar int vertex_indices" + std::string(_NL_) + "" << + "property uchar red" + std::string(_NL_) + "" << + "property uchar green" + std::string(_NL_) + "" << + "property uchar blue" + std::string(_NL_) + "" << + "property uchar alpha" + std::string(_NL_) + "" << + "end_header" + std::string(_NL_) + ""; + } + + void add_ply_header_mesh_no_color( + std::stringstream& stream, + const std::size_t num_vertices, + const std::size_t num_faces) const { + + stream << + "ply" + std::string(_NL_) + "" << + "format ascii 1.0" + std::string(_NL_) + "" << + "element vertex " << num_vertices << "" + std::string(_NL_) + "" << + "property double x" + std::string(_NL_) + "" << + "property double y" + std::string(_NL_) + "" << + "property double z" + std::string(_NL_) + "" << + "element face " << num_faces << "" + std::string(_NL_) + "" << + "property list ushort int vertex_indices" + std::string(_NL_) + "" << + "end_header" + std::string(_NL_) + ""; + } +}; + +template +void dump_volume( + const DS& data, + const std::vector& pfaces, + const std::string file_name, + const bool use_colors = true, + const std::size_t volume_index = 0) { + + using Point_3 = typename DS::Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + std::vector colors; + + colors.reserve(pfaces.size()); + polygons.reserve(pfaces.size()); + + Saver saver; + for (const auto& pface : pfaces) { + const auto pvertices = data.pvertices_of_pface(pface); + const auto color = saver.get_idx_color(volume_index); + polygon.clear(); + for (const auto pvertex : pvertices) { + polygon.push_back(data.point_3(pvertex)); + } + if (use_colors) { + colors.push_back(color); + } + else { + colors.push_back(saver.get_idx_color(0)); + } + CGAL_assertion(polygon.size() >= 3); + polygons.push_back(polygon); + } + CGAL_assertion(colors.size() == pfaces.size()); + CGAL_assertion(polygons.size() == pfaces.size()); + + saver.export_polygon_soup_3(polygons, colors, file_name); +} + +template +void dump_visi( + const DS& data, + const std::vector& pfaces, + const std::string &file_name, + const FT color) { + + using Point_3 = typename DS::Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + std::vector colors; + + colors.reserve(pfaces.size()); + polygons.reserve(pfaces.size()); + + const CGAL::IO::Color low(255, 255, 255); + const CGAL::IO::Color high(0, 0, 255); + + Saver saver; + for (const auto& pface : pfaces) { + const auto pvertices = data.pvertices_of_pface(pface); + polygon.clear(); + for (const auto pvertex : pvertices) { + polygon.push_back(data.point_3(pvertex)); + } + + colors.push_back(CGAL::IO::Color(static_cast((1 - color) * low[0] + color * high[0]), static_cast((1 - color) * low[1] + color * high[1]), static_cast((1 - color) * low[2] + color * high[2]), ((color > 0.5) ? 150 : 25))); + + CGAL_assertion(polygon.size() >= 3); + polygons.push_back(polygon); + } + CGAL_assertion(colors.size() == pfaces.size()); + CGAL_assertion(polygons.size() == pfaces.size()); + + saver.export_polygon_soup_3(polygons, colors, file_name); +} + +template +void dump_volumes(const DS& data, const std::string tag = std::string()) { + + using Point_3 = typename DS::Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + std::vector colors; + + Saver saver; + for (std::size_t i = 0; i < data.volumes().size(); ++i) { + const auto& volume = data.volumes()[i]; + const auto color = saver.get_idx_color(i); + + colors.clear(); + polygons.clear(); + for (const auto& pface : volume.pfaces) { + polygon.clear(); + for (const auto pvertex : data.pvertices_of_pface(pface)) { + polygon.push_back(data.point_3(pvertex)); + } + CGAL_assertion(polygon.size() >= 3); + polygons.push_back(polygon); + colors.push_back(color); + } + + const std::string file_name = + (tag != std::string() ? tag + "-" : "") + std::to_string(i); + saver.export_polygon_soup_3(polygons, colors, file_name); + } +} +/* + +template +void dump_volumes_ksp(const KSP& ksp, const std::string tag = std::string()) { + using Point_3 = typename KSP::Point_3; + using Index = typename KSP::Index; + std::vector< std::vector > polygons; + std::vector colors; + + std::vector faces_of_volume; + std::vector pts_of_face; + + Saver saver; + for (std::size_t i = 0; i < ksp.number_of_volumes(); ++i) { + faces_of_volume.clear(); + polygons.clear(); + colors.clear(); + + const auto color = saver.get_idx_color(i); + ksp.faces(i, std::back_inserter(faces_of_volume)); + + colors.clear(); + polygons.clear(); + for (const Index& f : faces_of_volume) { + pts_of_face.clear(); + ksp.vertices(f, std::back_inserter(pts_of_face)); + + polygons.push_back(pts_of_face); + colors.push_back(color); + } + + const std::string file_name = tag + std::to_string(i); + saver.export_polygon_soup_3(polygons, colors, file_name); + } +} +*/ +template +void dump_polygon(const std::vector& pts, const std::string& filename) { + Saver saver; + std::vector > pts2; + pts2.push_back(pts); + + saver.export_polygon_soup_3(pts2, filename); +} + +void dump_polygon(const std::vector& pts, const std::string& filename) { + Saver saver; + std::vector > pts2; + pts2.push_back(pts); + + saver.export_polygon_soup_3(pts2, filename); +} +void dump_polygona(const std::vector& pts, const std::string& filename) { + Saver saver; + std::vector > pts2; + pts2.push_back(pts); + + saver.export_polygon_soup_3(pts2, filename); +} + +void dump_polygons(const std::vector >& pts, const std::string& filename) { + Saver saver; + + saver.export_polygon_soup_3(pts, filename); +} +void dump_polygons(const std::vector > >& pts, const std::string& filename) { + Saver saver; + + saver.export_polygon_soup_3(pts, filename); +} + +void dump_indexed_triangles(const std::vector& pts, const std::vector& tris, const std::string& filename) { + Saver saver; + + saver.export_indexed_triangles_3(pts, tris, filename); +} + +void dump_indexed_polygons(const std::vector& pts, const std::vector >& polys, const std::string& filename) { + Saver saver; + + saver.export_indexed_polygons_3(pts, polys, filename); +} + + void dump_polygons(const std::vector >& pts, const std::vector& colors, const std::string& filename) { + Saver saver; + + saver.export_polygon_soup_3(pts, colors, filename); +} + +template +void dump_polygon( + const DS& data, + const std::size_t sp_idx, + const Polygon_2& input, + const std::string name) { + + using Kernel = typename DS::Kernel; + using Point_3 = typename Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + for (const auto& point_2 : input) { + polygon.push_back(data.to_3d(sp_idx, point_2)); + } + polygons.push_back(polygon); + Saver saver; + saver.export_polygon_soup_3(polygons, name); +} + +template +void dump_polygons( + const DS& data, + const Polygon_2& input,// std::map< std::size_t, std::pair > polygons; + const std::string name) { + + using Kernel = typename DS::Kernel; + using Point_3 = typename Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + for (const auto& pair : input) { + for (const auto &point2d : pair.second.first) + polygon.push_back(data.to_3d(pair.first, point2d)); + polygons.push_back(polygon); + polygon.clear(); + } + Saver saver; + saver.export_polygon_soup_3(polygons, name); +} + +void dump_points(const std::vector& pts, const std::vector& normals, const std::vector& colors, const std::string& filename) { + Saver saver; + saver.export_points_3(pts, normals, colors, filename); +} + +template +void dump_ifaces(const DS& data, const std::string tag = std::string()) { + // write all polygons into a separate ply with support plane index and iface index + for (std::size_t sp_idx = data.number_of_support_planes(); sp_idx++;) { + for (typename DS::IFace f : data.support_plane(sp_idx).ifaces()) { + Saver saver; + std::vector > pts(1); + for (auto v : data.igraph().face(f).vertices) + pts.back().push_back(data.igraph().point_3(v)); + saver.export_polygon_soup_3(pts, tag + "-" + std::to_string(sp_idx) + "-" + std::to_string(f)); + } + } +} +/* + +template +void dump_polygon(const DS& data, PTS pts, std::string tag = std::string()) { + // write all polygons into a separate ply with support plane index and iface index + Saver saver; + saver.export_polygon_soup_3(pts, tag); +}*/ + +template +void dump_pface( + const DS& data, + const PFace& pface, + const std::string name) { + + using Kernel = typename DS::Kernel; + using Point_3 = typename Kernel::Point_3; + std::vector polygon; + std::vector< std::vector > polygons; + for (const auto pvertex : data.pvertices_of_pface(pface)) { + polygon.push_back(data.point_3(pvertex)); + } + CGAL_assertion(polygon.size() >= 3); + polygons.push_back(polygon); + Saver saver; + saver.export_polygon_soup_3(polygons, name); +} + +template +void dump_pfaces( + const DS& data, + const std::vector& pfaces, + const std::string name) { + + using Kernel = typename DS::Kernel; + using Point_3 = typename Kernel::Point_3; + std::vector< std::vector > polygons; + for (auto pface : pfaces) { + std::vector polygon; + for (const auto pvertex : data.pvertices_of_pface(pface)) { + polygon.push_back(data.point_3(pvertex)); + } + CGAL_assertion(polygon.size() >= 3); + polygons.push_back(polygon); + } + Saver saver; + saver.export_polygon_soup_3(polygons, name); +} + +template +void dump_pedge( + const DS& data, + const PEdge& pedge, + const std::string name) { + + using Kernel = typename DS::Kernel; + using Segment_3 = typename Kernel::Segment_3; + const std::vector segments = { data.segment_3(pedge) }; + Saver saver; + saver.export_segments_3(segments, name); +} + +template +void dump_info( + const DS& data, + const PFace& pface, + const PEdge& pedge, + const std::vector& nfaces, + const std::string &suffix) { + + std::cout << "DEBUG: number of found nfaces: " << nfaces.size() << std::endl; + dump_pface(data, pface, "face-curr-" + suffix); + dump_pedge(data, pedge, "face-edge-" + suffix); + for (std::size_t i = 0; i < nfaces.size(); ++i) { + dump_pface(data, nfaces[i], "nface-" + std::to_string(i) + "-" + suffix); + } +} + +template +void dump_frame( + const std::vector& points, + const std::string name) { + + using Kernel = typename Kernel_traits::Kernel; + using Segment_3 = typename Kernel::Segment_3; + std::vector segments; + segments.reserve(points.size() - 1); + for (std::size_t i = 1; i < points.size(); ++i) + segments.push_back(Segment_3(points[0], points[i])); + Saver saver; + saver.export_segments_3(segments, name); +} + +template +void dump_cdt( + const DS& data, const std::size_t sp_idx, const CDT& cdt, std::string file_name) { + + using Point_3 = typename DS::Kernel::Point_3; + using Vertex_handle = typename CDT::Vertex_handle; + + using Mesh_3 = CGAL::Surface_mesh; + using VIdx = typename Mesh_3::Vertex_index; + using FIdx = typename Mesh_3::Face_index; + using UM = typename Mesh_3::template Property_map; + + Mesh_3 mesh; + UM red = mesh.template add_property_map("red" , 125).first; + UM green = mesh.template add_property_map("green", 125).first; + UM blue = mesh.template add_property_map("blue" , 125).first; + + std::map map_v2i; + for (auto vit = cdt.finite_vertices_begin(); vit != cdt.finite_vertices_end(); ++vit) { + const auto& ipoint = vit->point(); + map_v2i.insert(std::make_pair( + vit, mesh.add_vertex(data.support_plane(sp_idx).to_3d(ipoint)))); + } + + for (auto fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) { + std::array vertices; + for (int i = 0; i < 3; ++i) { + vertices[i] = map_v2i[fit->vertex(i)]; + } + + const auto face = mesh.add_face(vertices); + CGAL::Random rand(fit->info().index); + if (fit->info().index != std::size_t(-1)) { + red[face] = (unsigned char)(rand.get_int(32, 192)); + green[face] = (unsigned char)(rand.get_int(32, 192)); + blue[face] = (unsigned char)(rand.get_int(32, 192)); + } + } + + file_name += "support-cdt-" + std::to_string(sp_idx) + ".ply"; + std::ofstream out(file_name); + out.precision(20); + CGAL::IO::write_PLY(out, mesh); + out.close(); +} + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_DEBUG_H diff --git a/Kinetic_space_partition/include/CGAL/KSP/parameters.h b/Kinetic_space_partition/include/CGAL/KSP/parameters.h new file mode 100644 index 00000000000..b3586048da5 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP/parameters.h @@ -0,0 +1,48 @@ +// Copyright (c) 2021 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Simon Giraudot, Dmitry Anisimov + +#ifndef CGAL_KSP_PARAMETERS_H +#define CGAL_KSP_PARAMETERS_H + +#include + +namespace CGAL { +namespace KSP { +namespace internal { + +template +struct Parameters_3 { + + unsigned int k = 1; // k intersections + + // Octree parameters for subdivison of input data into kinetic subpartitions + unsigned int max_octree_depth = 3; + unsigned int max_octree_node_size = 40; + + FT bbox_dilation_ratio = FT(11) / FT(10); // ratio to enlarge bbox + + bool reorient_bbox = false; // true - optimal bounding box, false - axis aligned + + // All files are saved in the current build directory. + bool verbose = false; // print basic verbose information + bool debug = false; // print all steps and substeps + export initial and final configurations + + // See also global tolerance inside utils.h! (set to 0) + Parameters_3(const bool v = true, const bool d = false) : + verbose(v), debug(d) { } +}; + +} // namespace internal +} // namespace KSP +} // namespace CGAL + +#endif // CGAL_KSP_PARAMETERS_H diff --git a/Kinetic_space_partition/include/CGAL/KSP/utils.h b/Kinetic_space_partition/include/CGAL/KSP/utils.h new file mode 100644 index 00000000000..d8e99ddddc2 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP/utils.h @@ -0,0 +1,310 @@ +// Copyright (c) 2020 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Simon Giraudot, Dmitry Anisimov + +#ifndef CGAL_KSP_UTILS_H +#define CGAL_KSP_UTILS_H + +#include + +// STL includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// CGAL includes. +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// Boost includes. +#include + +namespace CGAL { +namespace KSP { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +// Convert point to string. +template +const std::string to_string(const Point_d& p) { + std::ostringstream oss; + oss.precision(20); + oss << p; + return oss.str(); +} + +// Distance between two points. +template +decltype(auto) distance(const Point_d& p, const Point_d& q) { + using Traits = typename Kernel_traits::Kernel; + using FT = typename Traits::FT; + const FT sq_dist = CGAL::squared_distance(p, q); + return static_cast(CGAL::approximate_sqrt(sq_dist)); +} + +// Project 3D point onto 2D plane. +template +typename Kernel_traits::Kernel::Point_2 +point_2_from_point_3(const Point_3& point_3) { + return typename Kernel_traits::Kernel::Point_2( + point_3.x(), point_3.y()); +} + +// Get 3D point from a 2D point. +template +typename Kernel_traits::Kernel::Point_3 +point_3_from_point_2(const Point_2& point_2) { + return typename Kernel_traits::Kernel::Point_3( + point_2.x(), point_2.y(), typename Kernel_traits::Kernel::FT(0)); +} + +// Normalize vector. +template +inline const Vector_d normalize(const Vector_d& v) { + using Traits = typename Kernel_traits::Kernel; + using FT = typename Traits::FT; + const FT dot_product = CGAL::abs(v * v); + //CGAL_assertion(dot_product != FT(0)); + return v / static_cast(CGAL::approximate_sqrt(dot_product)); +} + + +// Intersections. Used only in the 2D version. +// For the 3D version, see conversions.h! +template +inline bool intersection( + const Type1& t1, const Type2& t2, ResultType& result) { + + const auto inter = intersection(t1, t2); + if (!inter) return false; + + if (CGAL::assign(result, inter)) + return true; + + return false; +} + +template +inline const ResultType intersection(const Type1& t1, const Type2& t2) { + + ResultType out; + CGAL_assertion_code(const bool is_intersection_found =) intersection(t1, t2, out); + CGAL_assertion(is_intersection_found); + return out; +} + +// Get boundary points from a set of points. +template +void boundary_points_on_line_2( + const std::vector& input_range, + const std::vector& indices, + const Line_2& line, Point_2& p, Point_2& q) { + + using Traits = typename Kernel_traits::Kernel; + using FT = typename Traits::FT; + using Vector_2 = typename Traits::Vector_2; + + FT min_proj_value = (std::numeric_limits::max)(); + FT max_proj_value = -min_proj_value; + + const auto ref_vector = line.to_vector(); + const auto& ref_point = input_range[indices.front()]; + + for (const std::size_t index : indices) { + const auto& query = input_range[index]; + const auto point = line.projection(query); + const Vector_2 curr_vector(ref_point, point); + const FT value = CGAL::scalar_product(curr_vector, ref_vector); + + if (value < min_proj_value) { + min_proj_value = value; + p = point; + } + if (value > max_proj_value) { + max_proj_value = value; + q = point; + } + } +} + +// Angles. + +// Converts radians to degrees. +template +const FT degrees_2(const FT angle_rad) { + return angle_rad * FT(180) / static_cast(CGAL_PI); +} + +// Computes an angle in degrees between two directions. +template +const typename Kernel_traits::Kernel::FT +compute_angle_2(const Direction_2& dir1, const Direction_2& dir2) { + + using Traits = typename Kernel_traits::Kernel; + using FT = typename Traits::FT; + + const auto v1 = dir2.to_vector(); + const auto v2 = -dir1.to_vector(); + + const FT det = CGAL::determinant(v1, v2); + const FT dot = CGAL::scalar_product(v1, v2); + const FT angle_rad = static_cast( + std::atan2(CGAL::to_double(det), CGAL::to_double(dot))); + const FT angle_deg = degrees_2(angle_rad); + return angle_deg; +} + +// Converts an angle in degrees from the range [-180, 180] +// into the mod 90 angle. +template +const FT convert_angle_2(const FT angle_2) { + + FT angle = angle_2; + if (angle > FT(90)) angle = FT(180) - angle; + else if (angle < -FT(90)) angle = FT(180) + angle; + return angle; +} + +// Computes a positive angle in degrees that +// is always in the range [0, 90]. +template +const typename Kernel_traits::Kernel::FT +angle_2(const Direction_2& dir1, const Direction_2& dir2) { + const auto angle_2 = compute_angle_2(dir1, dir2); + return CGAL::abs(convert_angle_2(angle_2)); +} + +// Classes. +template +class Indexer { +public: + std::size_t operator()(const IVertex& ivertex) { + const auto pair = m_indices.insert( + std::make_pair(ivertex, m_indices.size())); + const auto& item = pair.first; + const std::size_t idx = item->second; + return idx; + } + void clear() { m_indices.clear(); } + +private: + std::map m_indices; +}; + +template< + typename GeomTraits, + typename InputRange, + typename NeighborQuery> +class Estimate_normals_2 { + +public: + using Traits = GeomTraits; + using Input_range = InputRange; + using Neighbor_query = NeighborQuery; + + using Kernel = Traits; + using FT = typename Kernel::FT; + using Vector_2 = typename Kernel::Vector_2; + using Line_2 = typename Kernel::Line_2; + + using Indices = std::vector; + + using IK = CGAL::Exact_predicates_inexact_constructions_kernel; + using IPoint_2 = typename IK::Point_2; + using ILine_2 = typename IK::Line_2; + using Converter = CGAL::Cartesian_converter; + + Estimate_normals_2( + const Input_range& input_range, + const Neighbor_query& neighbor_query) : + m_input_range(input_range), + m_neighbor_query(neighbor_query) { + + CGAL_precondition(input_range.size() > 0); + } + + void get_normals(std::vector& normals) const { + + normals.clear(); + normals.reserve(m_input_range.size()); + + Indices neighbors; + for (std::size_t i = 0; i < m_input_range.size(); ++i) { + neighbors.clear(); + m_neighbor_query(i, neighbors); + const auto line = fit_line(neighbors); + auto normal = line.to_vector(); + normal = normal.perpendicular(CGAL::COUNTERCLOCKWISE); + normal = normalize(normal); + normals.push_back(normal); + } + CGAL_assertion(normals.size() == m_input_range.size()); + } + +private: + const Input_range& m_input_range; + const Neighbor_query& m_neighbor_query; + const Converter m_converter; + + const Line_2 fit_line(const Indices& indices) const { + CGAL_assertion(indices.size() > 0); + + std::vector points; + points.reserve(indices.size()); + for (const std::size_t index : indices) { + const auto& point = get(m_neighbor_query.point_map(), index); + points.push_back(m_converter(point)); + } + CGAL_assertion(points.size() == indices.size()); + + ILine_2 fitted_line; + IPoint_2 fitted_centroid; + CGAL::linear_least_squares_fitting_2( + points.begin(), points.end(), + fitted_line, fitted_centroid, + CGAL::Dimension_tag<0>()); + + const Line_2 line( + static_cast(fitted_line.a()), + static_cast(fitted_line.b()), + static_cast(fitted_line.c())); + return line; + } +}; + +#endif + +} // namespace internal +} // namespace KSP +} // namespace CGAL + +#endif // CGAL_KSP_UTILS_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h b/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h new file mode 100644 index 00000000000..db2dc5892a0 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Data_structure.h @@ -0,0 +1,1621 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_DATA_STRUCTURE_H +#define CGAL_KSP_3_DATA_STRUCTURE_H + +#include + +#include +#include + +// Internal includes. +#include +#include +#include + +#include +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Data_structure { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionKernel; + + using Support_plane = CGAL::KSP_3::internal::Support_plane; + using Intersection_graph = CGAL::KSP_3::internal::Intersection_graph; + using Face_event = typename Support_plane::Face_event; + + using FT = typename Kernel::FT; + using IkFT = typename Intersection_kernel::FT; + using Point_2 = typename Kernel::Point_2; + using IkPoint_2 = typename Intersection_kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + using IkPoint_3 = typename Intersection_kernel::Point_3; + using Segment_2 = typename Kernel::Segment_2; + using IkSegment_2 = typename Intersection_kernel::Segment_2; + using Segment_3 = typename Kernel::Segment_3; + using IkSegment_3 = typename Intersection_kernel::Segment_3; + using Vector_2 = typename Kernel::Vector_2; + using IkVector_2 = typename Intersection_kernel::Vector_2; + using Direction_2 = typename Kernel::Direction_2; + using IkDirection_2 = typename Intersection_kernel::Direction_2; + using Triangle_2 = typename Kernel::Triangle_2; + using Line_2 = typename Kernel::Line_2; + using IkLine_2 = typename Intersection_kernel::Line_2; + using Plane_3 = typename Kernel::Plane_3; + + using Polygon_2 = CGAL::Polygon_2; + using Parameters = KSP::internal::Parameters_3; + + using To_exact = CGAL::Cartesian_converter; + using From_exact = CGAL::Cartesian_converter; + +public: + using Mesh = typename Support_plane::Mesh; + using Vertex_index = typename Mesh::Vertex_index; + using Face_index = typename Mesh::Face_index; + using Edge_index = typename Mesh::Edge_index; + using Halfedge_index = typename Mesh::Halfedge_index; + + using PVertex = std::pair; + using PFace = std::pair; + using PEdge = std::pair; + + template + struct Make_PSimplex { + using argument_type = typename PSimplex::second_type; + using result_type = PSimplex; + + const std::size_t support_plane_idx; + Make_PSimplex(const std::size_t sp_idx) : + support_plane_idx(sp_idx) + { } + + const result_type operator()(const argument_type& arg) const { + return result_type(support_plane_idx, arg); + } + }; + + // ToDo:: check all kind of iterators/circulators + using PVertex_iterator = boost::transform_iterator, typename Mesh::Vertex_range::iterator>; + using PVertices = CGAL::Iterator_range; + + using PFace_iterator = boost::transform_iterator, typename Mesh::Face_range::iterator>; + using PFaces = CGAL::Iterator_range; + + using PEdge_iterator = boost::transform_iterator, typename Mesh::Edge_range::iterator>; + using PEdges = CGAL::Iterator_range; + + struct Halfedge_to_pvertex { + using argument_type = Halfedge_index; + using result_type = PVertex; + + const std::size_t support_plane_idx; + const Mesh& mesh; + + Halfedge_to_pvertex(const std::size_t sp_idx, const Mesh& m) : + support_plane_idx(sp_idx), + mesh(m) + { } + + const result_type operator()(const argument_type& arg) const { + return result_type(support_plane_idx, mesh.target(arg)); + } + }; + + using PVertex_of_pface_iterator = boost::transform_iterator >; + using PVertices_of_pface = CGAL::Iterator_range; + + struct Halfedge_to_pedge { + using argument_type = Halfedge_index; + using result_type = PEdge; + + const std::size_t support_plane_idx; + const Mesh& mesh; + + Halfedge_to_pedge(const std::size_t sp_idx, const Mesh& m) : + support_plane_idx(sp_idx), + mesh(m) + { } + + const result_type operator()(const argument_type& arg) const { + return result_type(support_plane_idx, mesh.edge(arg)); + } + }; + + struct Halfedge_to_pface { + using argument_type = Halfedge_index; + using result_type = PFace; + + const std::size_t support_plane_idx; + const Mesh& mesh; + + Halfedge_to_pface(const std::size_t sp_idx, const Mesh& m) : + support_plane_idx(sp_idx), + mesh(m) + { } + + const result_type operator()(const argument_type& arg) const { + return result_type(support_plane_idx, mesh.face(arg)); + } + }; + + // ToDo:: check all kind of iterators/circulators + using PEdge_around_pvertex_iterator = boost::transform_iterator >; + using PEdges_around_pvertex = CGAL::Iterator_range; + + using PEdge_of_pface_iterator = boost::transform_iterator >; + using PEdges_of_pface = CGAL::Iterator_range; + + using PFace_around_pvertex_iterator = boost::transform_iterator >; + using PFaces_around_pvertex = CGAL::Iterator_range; + + using IVertex = typename Intersection_graph::Vertex_descriptor; + using IEdge = typename Intersection_graph::Edge_descriptor; + using IFace = typename Intersection_graph::Face_descriptor; + + using IEdge_set = typename Intersection_graph::IEdge_set; + + using Index = std::pair; // first is partition index, second is volume index. Partition -1 indicates outside. 0-5 indicate which side of the bbox + + struct Volume_cell { + std::vector pfaces;// index compatible to faces and neighbors + std::vector faces;// Indices into m_face2vertices in m_data. + std::vector pface_oriented_outwards; + std::vector neighbors; + std::set pvertices; + std::size_t index = std::size_t(-1); + Point_3 centroid; + + FT inside = FT(1); + FT outside = FT(0); + FT weight = FT(0); + + FT inside_count = FT(0); + FT outside_count = FT(0); + + void add_pface(const PFace& pface, const int neighbor) { + pfaces.push_back(pface); + neighbors.push_back(neighbor); + } + void set_index(const std::size_t idx) { + index = idx; + } + void set_centroid(const Point_3& point) { + centroid = point; + } + }; + + struct Reconstructed_model { + std::vector pfaces; + void clear() { + pfaces.clear(); + } + }; + +private: + std::vector m_support_planes; + std::vector m_initial_support_planes; + Intersection_graph m_intersection_graph; + + std::vector > m_input_polygons; + + To_exact to_exact; + From_exact from_exact; + + const Parameters& m_parameters; + + std::string m_prefix; + + std::vector m_volumes; + std::vector m_vertices; + std::vector m_exact_vertices; + std::vector m_ivertex2vertex; // Used to map ivertices to m_vertices which only contain vertices of the finalized kinetic partition. + std::vector > m_face2volumes; + + std::map m_face2index; + std::vector > m_face2vertices; + std::vector m_part_of_initial; + std::map > m_pface_neighbors; + std::vector m_face2sp; + std::vector > m_sp2input_polygon; + std::map m_input_polygon_map; // Maps index of input polygon onto support plane indices. + Reconstructed_model m_reconstructed_model; + +public: + Data_structure(const Parameters& parameters, const std::string &prefix) : to_exact(), from_exact(), m_parameters(parameters), m_prefix(prefix) { + } + + template + static bool intersection(const Type1& t1, const Type2& t2, ResultType& result) { + const auto inter = CGAL::intersection(t1, t2); + if (!inter) return false; + if (CGAL::assign(result, inter)) + return true; + + return false; + } + + /******************************* + ** INITIALIZATION ** + ********************************/ + + void clear() { + m_support_planes.clear(); + m_intersection_graph.clear(); + + m_volumes.clear(); + m_pface_neighbors.clear(); + m_input_polygon_map.clear(); + m_reconstructed_model.clear(); + } + + void precompute_iedge_data() { + for (std::size_t i = 0; i < number_of_support_planes(); ++i) { + auto& unique_iedges = support_plane(i).unique_iedges(); + CGAL_assertion(unique_iedges.size() > 0); + + auto& iedges = this->iedges(i); + + iedges.clear(); + iedges.reserve(unique_iedges.size()); + std::copy(unique_iedges.begin(), unique_iedges.end(), std::back_inserter(iedges)); + unique_iedges.clear(); + } + } + + void initialization_done() { + m_intersection_graph.initialization_done(); + m_initial_support_planes.resize(m_support_planes.size()); + for (std::size_t i = 0; i < m_support_planes.size(); i++) + m_initial_support_planes[i] = m_support_planes[i].data(); + + } + void reset_to_initialization() { + m_intersection_graph.reset_to_initialization(); + + CGAL_assertion(m_support_planes.size() == m_initial_support_planes.size()); + for (std::size_t i = 0; i < m_support_planes.size(); i++) { + m_support_planes[i].data() = m_initial_support_planes[i]; + + m_support_planes[i].link_property_maps(); + } + + m_volumes.clear(); + m_vertices.clear(); + m_exact_vertices.clear(); + m_ivertex2vertex.clear(); + m_face2index.clear(); + m_face2vertices.clear(); + m_pface_neighbors.clear(); + m_face2sp.clear(); + } + + /******************************* + ** ACCESS ** + ********************************/ + + const std::vector >& input_polygons() const { + return m_input_polygons; + } + + int support_plane_index(const std::size_t polygon_index) const { + CGAL_assertion(m_input_polygon_map.find(polygon_index) != m_input_polygon_map.end()); + const std::size_t sp_idx = m_input_polygon_map.at(polygon_index); + return static_cast(sp_idx); + } + + std::size_t number_of_volumes() const { + return m_volumes.size(); + } + + /******************************* + ** GENERAL ** + ********************************/ + + std::map >& pface_neighbors() { return m_pface_neighbors; } + const std::map >& pface_neighbors() const { return m_pface_neighbors; } + std::map &face_to_index() { return m_face2index; } + std::vector& ivertex_to_index() { + if (m_ivertex2vertex.size() == 0) + m_ivertex2vertex.resize(m_intersection_graph.number_of_vertices(), -1); + + return m_ivertex2vertex; + } + std::vector >& face_to_volumes() { return m_face2volumes; } + const std::vector >& face_to_volumes() const { return m_face2volumes; } + std::vector& vertices() { return m_vertices; } + const std::vector& vertices() const { return m_vertices; } + std::vector& exact_vertices() { return m_exact_vertices; } + const std::vector& exact_vertices() const { return m_exact_vertices; } + std::vector >& face_to_vertices() { return m_face2vertices; } + const std::vector >& face_to_vertices() const { return m_face2vertices; } + + std::vector& face_is_part_of_input_polygon() { return m_part_of_initial; } + const std::vector& face_is_part_of_input_polygon() const { return m_part_of_initial; } + + std::vector& face_to_support_plane() { return m_face2sp; } + std::vector >& support_plane_to_input_polygon() { return m_sp2input_polygon; } + + const std::vector& support_planes() const { return m_support_planes; } + std::vector& support_planes() { return m_support_planes; } + + const Intersection_graph& igraph() const { return m_intersection_graph; } + Intersection_graph& igraph() { return m_intersection_graph; } + + const std::string& prefix() const { return m_prefix; } + + void resize(const std::size_t number_of_items) { + m_support_planes.resize(number_of_items); + } + + IkFT calculate_edge_intersection_time(std::size_t sp_idx, IEdge edge, Face_event &event) { + // Not need to calculate for border edges. + if (m_intersection_graph.iedge_is_on_bbox(edge)) + return 0; + + // Count faces + std::size_t numfaces = 0; + for (std::size_t i = 0; i < m_support_planes.size(); i++) + numfaces += m_support_planes[i].data().mesh.number_of_faces(); + + Support_plane& sp = m_support_planes[sp_idx]; + + To_exact to_exact; + + Point_2 centroid = sp.data().centroid; + IkPoint_2 centroid2 = to_exact(sp.data().centroid); + + typename Intersection_graph::Kinetic_interval& kinetic_interval = m_intersection_graph.kinetic_interval(edge, sp_idx); + + Point_2 s = sp.to_2d(from_exact(point_3(m_intersection_graph.source(edge)))); + IkPoint_2 s2 = sp.to_2d(point_3(m_intersection_graph.source(edge))); + Point_2 t = sp.to_2d(from_exact(point_3(m_intersection_graph.target(edge)))); + IkPoint_2 t2 = sp.to_2d(point_3(m_intersection_graph.target(edge))); + Vector_2 segment = t - s; + IkVector_2 segment2 = t2 - s2; + FT segment_length = CGAL::approximate_sqrt(segment * segment); + IkFT segment_length2 = CGAL::approximate_sqrt(segment2.squared_length()); + CGAL_assertion(segment_length > 0); + segment = segment / segment_length; + segment2 = segment2 / segment_length2; + Direction_2 to_source(s - centroid); + Direction_2 to_target(t - centroid); + IkDirection_2 to_source2(s2 - centroid2); + IkDirection_2 to_target2(t2 - centroid2); + + const std::size_t uninitialized = static_cast(-1); + std::size_t source_idx = uninitialized; + std::size_t target_idx = uninitialized; + + event.crossed_edge = edge; + event.support_plane = sp_idx; + + std::pair faces; + m_intersection_graph.get_faces(sp_idx, edge, faces); + + if (m_intersection_graph.face(faces.first).part_of_partition) + event.face = faces.second; + else + event.face = faces.first; + + for (std::size_t i = 0; i < sp.data().original_directions.size(); i++) { + if (source_idx == uninitialized && sp.data().original_directions[i] > to_source) + source_idx = i; + + if (target_idx == uninitialized && sp.data().original_directions[i] > to_target) + target_idx = i; + } + + source_idx = (source_idx == uninitialized) ? 0 : source_idx; + target_idx = (target_idx == uninitialized) ? 0 : target_idx; + + std::size_t num; + + // Vector_2 tt = to_target.vector(), ts = to_source.vector(); + IkVector_2 tt2 = to_target2.vector(), ts2 = to_source2.vector(); + bool ccw = (tt2.x() * ts2.y() - tt2.y() * ts2.x()) < 0; + + // Check whether the segment is cw or ccw oriented. + if (!ccw) { + std::size_t tmp = source_idx; + source_idx = target_idx; + target_idx = tmp; + + Point_2 tmp_p = s; + s = t; + t = tmp_p; + + IkPoint_2 tmp_p2 = s2; + s2 = t2; + t2 = tmp_p2; + } + + if (source_idx <= target_idx) + num = target_idx - source_idx; + else + num = (sp.data().original_directions.size() + target_idx - source_idx); + + std::vector time(num); + std::vector intersections(num); + std::vector intersections_bary(num); + + // Shooting rays to find intersection with line of IEdge + typename Intersection_kernel::Line_3 l3 = m_intersection_graph.line_3(edge); + const typename Intersection_kernel::Line_2 l = sp.to_2d(l3); + for (std::size_t i = 0; i < num; i++) { + std::size_t idx = (i + source_idx) % sp.data().original_directions.size(); + const auto result = CGAL::intersection(l, sp.data().original_rays[idx]); + if (!result) { + time[i] = (std::numeric_limits::max)(); + continue; + } + IkPoint_2 p; + FT diff = sp.data().original_vectors[idx].squared_length() - from_exact(sp.data().original_rays[idx].to_vector().squared_length()); + + if (CGAL::assign(p, result)) { + IkFT l = CGAL::approximate_sqrt(sp.data().original_vectors[idx].squared_length()); + + IkFT l2 = from_exact(CGAL::approximate_sqrt((p - sp.data().original_rays[idx].point(0)).squared_length())); + + IkFT l3 = (p - sp.data().original_rays[idx].point(0)) * sp.data().original_rays[idx].to_vector(); + time[i] = l3; + CGAL_assertion(0 <= time[i]); + intersections[i] = p; + intersections_bary[i] = abs(((p - s2) * segment2)) / segment_length2; + if (!ccw) + intersections_bary[i] = 1.0 - intersections_bary[i]; + } + // If the intersection is a segment, it can be safely ignored as there are also two intersections with the adjacent edges. + } + + // Calculate pedge vs ivertex collision + IkFT edge_time[2]; + + // Source edge time + std::size_t adjacent = (source_idx + sp.data().original_vertices.size() - 1) % sp.data().original_vertices.size(); + Vector_2 dir = sp.data().original_vertices[source_idx] - sp.data().original_vertices[adjacent]; + dir = dir / CGAL::approximate_sqrt(dir * dir); + + // Orthogonal direction matching the direction of the adjacent vertices + dir = Vector_2(dir.y(), -dir.x()); + + // Moving speed matches the speed of adjacent vertices + FT speed = (dir * sp.data().original_vectors[source_idx]); + + if (speed < 0) + speed = -speed; + + // Distance from edge to endpoint of iedge + FT dist = (s - sp.data().original_vertices[source_idx]) * dir; + + edge_time[0] = dist / speed; + + // Target edge time + adjacent = (target_idx + sp.data().original_vertices.size() - 1) % sp.data().original_vertices.size(); + dir = sp.data().original_vertices[target_idx] - sp.data().original_vertices[adjacent]; + dir = dir / CGAL::approximate_sqrt(dir * dir); + + // Orthogonal direction matching the direction of the adjacent vertices + dir = Vector_2(dir.y(), -dir.x()); + + // Moving speed matches the speed of adjacent vertices + speed = (dir * sp.data().original_vectors[target_idx]); + + if (speed < 0) + speed = -speed; + + // Distance from edge to endpoint of iedge + dist = (t - sp.data().original_vertices[target_idx]) * dir; + + edge_time[1] = dist / speed; + + // Fill event structure and kinetic intervals. + if (ccw) + kinetic_interval.push_back(std::pair(0, edge_time[0])); + else + kinetic_interval.push_back(std::pair(0, edge_time[1])); + + event.time = kinetic_interval.back().second; + event.intersection_bary = 0; + + for (std::size_t i = 0; i < num; i++) { + kinetic_interval.push_back(std::pair(intersections_bary[i], time[i])); + if (event.time > time[i]) { + event.time = time[i]; + event.intersection_bary = intersections_bary[i]; + } + } + + if (ccw) + kinetic_interval.push_back(std::pair(1, edge_time[1])); + else + kinetic_interval.push_back(std::pair(1, edge_time[0])); + + if (event.time > kinetic_interval.back().second) { + event.time = kinetic_interval.back().second; + event.intersection_bary = 1; + } + + + if (kinetic_interval.size() > 4) { + if (kinetic_interval[2].first > kinetic_interval[1].first) { + int a; + a = 2; + } + } + + CGAL_assertion(0 <= event.intersection_bary && event.intersection_bary <= 1); + + return event.time; + } + + template + void fill_event_queue(Queue& queue) { + // Count faces + std::size_t faces = 0; + for (std::size_t i = 0; i < m_support_planes.size(); i++) + faces += m_support_planes[i].data().mesh.number_of_faces(); + + for (std::size_t sp_idx = 6; sp_idx < m_support_planes.size(); sp_idx++) { + std::vector border; + m_support_planes[sp_idx].get_border(m_intersection_graph, border); + + for (IEdge edge : border) { + if (m_intersection_graph.has_crossed(edge, sp_idx)) + continue; + + Face_event fe; + IkFT t = calculate_edge_intersection_time(sp_idx, edge, fe); + if (t > 0) { + queue.push(fe); + } + } + } + } + + std::vector& volumes() { return m_volumes; } + const std::vector& volumes() const { return m_volumes; } + + const std::vector& volume(std::size_t volume_index) { + return m_volumes[volume_index].faces; + } + + const std::vector &face(std::size_t face_index) const { return m_face2vertices[face_index]; } + const Point_3& vertex(std::size_t vertex_index) const { return m_vertices[vertex_index]; } + + Reconstructed_model& reconstructed_model() { return m_reconstructed_model; } + const Reconstructed_model& reconstructed_model() const { return m_reconstructed_model; } + + /******************************* + ** SUPPORT PLANES ** + ********************************/ + + template + const Support_plane& support_plane(const PSimplex& psimplex) const { return support_plane(psimplex.first); } + const Support_plane& support_plane(const std::size_t idx) const { return m_support_planes[idx]; } + + template + Support_plane& support_plane(const PSimplex& psimplex) { return support_plane(psimplex.first); } + Support_plane& support_plane(const std::size_t idx) { return m_support_planes[idx]; } + + template + const Mesh& mesh(const PSimplex& psimplex) const { return mesh(psimplex.first); } + const Mesh& mesh(const std::size_t support_plane_idx) const { return support_plane(support_plane_idx).mesh(); } + + template + Mesh& mesh(const PSimplex& psimplex) { return mesh(psimplex.first); } + Mesh& mesh(const std::size_t support_plane_idx) { return support_plane(support_plane_idx).mesh(); } + + std::size_t number_of_support_planes() const { + return m_support_planes.size(); + } + + bool is_bbox_support_plane(const std::size_t support_plane_idx) const { + return (support_plane_idx < 6); + } + + template + std::pair add_support_plane(const PointRange& polygon, const bool is_bbox, const typename Intersection_kernel::Plane_3& plane) { + const Support_plane new_support_plane(polygon, is_bbox, plane); + const std::size_t uninitialized = static_cast(-1); + std::size_t support_plane_idx = uninitialized; + + for (std::size_t i = 0; i < number_of_support_planes(); ++i) { + if (new_support_plane == support_plane(i)) { + support_plane_idx = i; + return std::make_pair(support_plane_idx, false); + } + } + + if (support_plane_idx == uninitialized) { + support_plane_idx = number_of_support_planes(); + m_support_planes.push_back(new_support_plane); + } + + intersect_with_bbox(support_plane_idx); + + if (m_sp2input_polygon.size() <= number_of_support_planes()) + m_sp2input_polygon.resize(number_of_support_planes()); + + return std::make_pair(support_plane_idx, true); + } + + template + std::pair add_support_plane(const PointRange& polygon, const bool is_bbox) { + const Support_plane new_support_plane(polygon, is_bbox); + const std::size_t uninitialized = static_cast(- 1); + std::size_t support_plane_idx = uninitialized; + + for (std::size_t i = 0; i < number_of_support_planes(); ++i) { + if (new_support_plane == support_plane(i)) { + support_plane_idx = i; + return std::make_pair(support_plane_idx, false); + } + } + + if (support_plane_idx == uninitialized) { + support_plane_idx = number_of_support_planes(); + m_support_planes.push_back(new_support_plane); + } + + intersect_with_bbox(support_plane_idx); + + if (m_sp2input_polygon.size() <= number_of_support_planes()) + m_sp2input_polygon.resize(number_of_support_planes()); + + return std::make_pair(support_plane_idx, true); + } + + void intersect_with_bbox(const std::size_t sp_idx) { + if (is_bbox_support_plane(sp_idx)) return; + + typename Intersection_kernel::FT bbox_center_x = 0, bbox_center_y = 0, bbox_center_z = 0; + for (std::size_t i = 0; i < 8; i++) { + IkPoint_3 tmp = point_3(IVertex(i)); + bbox_center_x += tmp.x(); + bbox_center_y += tmp.y(); + bbox_center_z += tmp.z(); + } + + IkPoint_3 bbox_center(bbox_center_x * 0.125, bbox_center_y * 0.125, bbox_center_z * 0.125); + + // Intersect current plane with all bbox iedges. + IkPoint_3 point; + Point_3 p1; + const auto& sp = support_plane(sp_idx); + const auto& plane = sp.exact_plane(); + + using IEdge_vec = std::vector; + using IPair = std::pair; + using Pair = std::pair; + + std::vector polygon; + polygon.reserve(3); + const auto all_iedges = m_intersection_graph.edges(); + for (const auto iedge : all_iedges) { + const auto segment = segment_3(iedge); + + if (!intersection(plane, segment, point)) + continue; + + const auto isource = source(iedge); + const auto itarget = target(iedge); + const bool is_isource = KSP::internal::distance(point, point_3(isource)) == 0; + const bool is_itarget = KSP::internal::distance(point, point_3(itarget)) == 0; + + std::vector iedges; + if (is_isource) { + CGAL_assertion(!is_itarget); + const auto inc_edges = m_intersection_graph.incident_edges(isource); + CGAL_assertion(iedges.size() == 0); + iedges.reserve(inc_edges.size()); + std::copy(inc_edges.begin(), inc_edges.end(), std::back_inserter(iedges)); + CGAL_assertion(iedges.size() == inc_edges.size()); + polygon.push_back(std::make_pair(point, std::make_pair(isource, iedges))); + } + + if (is_itarget) { + CGAL_assertion(!is_isource); + const auto inc_edges = m_intersection_graph.incident_edges(itarget); + CGAL_assertion(iedges.size() == 0); + iedges.reserve(inc_edges.size()); + std::copy(inc_edges.begin(), inc_edges.end(), std::back_inserter(iedges)); + CGAL_assertion(iedges.size() == inc_edges.size()); + polygon.push_back(std::make_pair(point, std::make_pair(itarget, iedges))); + } + + if (!is_isource && !is_itarget) { + CGAL_assertion(iedges.size() == 0); + iedges.push_back(iedge); + polygon.push_back(std::make_pair(point, std::make_pair(null_ivertex(), iedges))); + } + } + + // Sort the points to get an oriented polygon. + typename Intersection_kernel::FT x = 0, y = 0, z = 0, f = 1.0 / polygon.size(); + for (const auto& p : polygon) { + x += p.first.x(); + y += p.first.y(); + z += p.first.z(); + } + x *= f; + y *= f; + z *= f; + IkPoint_2 mid = sp.to_2d(IkPoint_3(x, y, z)); + + std::sort(polygon.begin(), polygon.end(), + [&](const Pair& a, const Pair& b) { + const auto a2 = sp.to_2d(a.first); + const auto b2 = sp.to_2d(b.first); + const IkSegment_2 sega(mid, a2); + const IkSegment_2 segb(mid, b2); + return (IkDirection_2(sega) < IkDirection_2(segb)); + }); + + remove_equal_points(polygon, 0); + + is_valid_polygon(sp_idx, polygon); + + // Find common planes. + std::vector vertices; + std::vector common_bbox_planes_idx; + std::map map_lines_idx; // Maps edges between vertices to line_idx + + const std::size_t n = polygon.size(); + common_bbox_planes_idx.reserve(n); + vertices.reserve(n); + + std::vector< std::set > all_iplanes; + all_iplanes.reserve(n); + for (std::size_t i = 0; i < n; ++i) { + const auto& item = polygon[i].second; + const auto& iedges = item.second; + + std::set iplanes; + for (const auto& iedge : iedges) { + const auto& planes = m_intersection_graph.intersected_planes(iedge); + iplanes.insert(planes.begin(), planes.end()); + } + + CGAL_assertion(iplanes.size() >= 2); + all_iplanes.push_back(iplanes); + } + CGAL_assertion(all_iplanes.size() == n); + + for (std::size_t i = 0; i < n; ++i) { + const std::size_t ip = (i + 1) % n; + const auto& item = polygon[i].second; + + const auto& iplanes0 = all_iplanes[i]; + const auto& iplanes1 = all_iplanes[ip]; + + const std::size_t uninitialized = static_cast(-1); + std::size_t common_bbox_plane_idx = uninitialized; + bool dump = false; + const std::function lambda = + [&](const std::size_t& idx) { + if (idx < 6) { + + if (common_bbox_plane_idx != uninitialized) + dump = true; + common_bbox_plane_idx = idx; + } + }; + + std::set_intersection( + iplanes0.begin(), iplanes0.end(), + iplanes1.begin(), iplanes1.end(), + boost::make_function_output_iterator(lambda) + ); + + if (dump) { + From_exact from_exact; + + std::ofstream vout("bug.polylines.txt"); + vout.precision(20); + vout << "2 "; + vout << " " << from_exact(polygon[i].first); + vout << " " << from_exact(polygon[ip].first); + vout << std::endl; + vout.close(); + } + + CGAL_assertion(common_bbox_plane_idx != uninitialized); + common_bbox_planes_idx.push_back(common_bbox_plane_idx); + + const auto pair = map_lines_idx.insert( + std::make_pair(common_bbox_plane_idx, uninitialized)); + const bool is_inserted = pair.second; + if (is_inserted) { + typename Intersection_kernel::Line_3 line; + CGAL_assertion_code(bool intersect =) intersection(plane, m_support_planes[common_bbox_plane_idx].exact_plane(), line); + CGAL_assertion(intersect); + pair.first->second = m_intersection_graph.add_line(line); + } + + if (item.first != null_ivertex()) { + vertices.push_back(item.first); + } else { + CGAL_assertion(item.first == null_ivertex()); + vertices.push_back( + m_intersection_graph.add_vertex(polygon[i].first).first); + } + } + CGAL_assertion(common_bbox_planes_idx.size() == n); + CGAL_assertion(vertices.size() == n); + + // Insert, split iedges. + for (std::size_t i = 0; i < n; ++i) { + const std::size_t ip = (i + 1) % n; + const auto& item = polygon[i].second; + + const std::size_t common_bbox_plane_idx = common_bbox_planes_idx[i]; + const auto new_iedge = m_intersection_graph.add_edge(vertices[i], vertices[ip], sp_idx).first; + + m_intersection_graph.intersected_planes(new_iedge).insert(common_bbox_plane_idx); + CGAL_assertion(map_lines_idx.find(common_bbox_plane_idx) != map_lines_idx.end()); + m_intersection_graph.set_line(new_iedge, map_lines_idx.at(common_bbox_plane_idx)); + support_plane(sp_idx).unique_iedges().insert(new_iedge); + support_plane(common_bbox_plane_idx).unique_iedges().insert(new_iedge); + + // No further treatment necessary for exact intersections at vertices of edges. + + if (item.first == null_ivertex()) { // edge case, split + const auto& iplanes = all_iplanes[i]; + CGAL_assertion(iplanes.size() >= 2); + CGAL_assertion(item.second.size() == 1); + const auto& iedge = item.second[0]; + for (const std::size_t plane_idx : iplanes) { + support_plane(plane_idx).unique_iedges().erase(iedge); + } + const auto edges = m_intersection_graph.split_edge(iedge, vertices[i]); + + const auto& iplanes0 = m_intersection_graph.intersected_planes(edges.first); + for (const std::size_t plane_idx : iplanes0) { + support_plane(plane_idx).unique_iedges().insert(edges.first); + } + + const auto& iplanes1 = m_intersection_graph.intersected_planes(edges.second); + for (const std::size_t plane_idx : iplanes1) { + support_plane(plane_idx).unique_iedges().insert(edges.second); + } + } + } + } + + template + void add_bbox_polygon(const PointRange& polygon) { + bool is_added = true; + const std::size_t uninitialized = static_cast(-1); + std::size_t support_plane_idx = uninitialized; + std::tie(support_plane_idx, is_added) = add_support_plane(polygon, true); + CGAL_assertion(is_added); + CGAL_assertion(support_plane_idx != uninitialized); + + std::array ivertices; + std::array points; + for (std::size_t i = 0; i < 4; ++i) { + points[i] = from_exact(support_plane(support_plane_idx).to_2d(polygon[i])); + ivertices[i] = m_intersection_graph.add_vertex(polygon[i]).first; + } + + const auto vertices = + support_plane(support_plane_idx).add_bbox_polygon(points, ivertices); + + for (std::size_t i = 0; i < 4; ++i) { + const auto pair = m_intersection_graph.add_edge(ivertices[i], ivertices[(i + 1) % 4], support_plane_idx); + const auto& iedge = pair.first; + const bool is_inserted = pair.second; + if (is_inserted) { + typename Intersection_kernel::Line_3 line(polygon[i], polygon[(i + 1) % 4]); + m_intersection_graph.set_line(iedge, m_intersection_graph.add_line(line)); + } + + support_plane(support_plane_idx).set_iedge(vertices[i], vertices[(i + 1) % 4], iedge); + support_plane(support_plane_idx).unique_iedges().insert(iedge); + } + } + + void add_input_polygon( const std::size_t support_plane_idx, const std::vector& input_indices, const std::vector& polygon) { + std::vector< std::pair > points; + points.reserve(polygon.size()); + for (const auto& point : polygon) { + points.push_back(std::make_pair(point, true)); + } + CGAL_assertion(points.size() == polygon.size()); + + preprocess(points); + sort_points_by_direction(points); + support_plane(support_plane_idx). + add_input_polygon(points, input_indices); + for (const std::size_t input_index : input_indices) { + m_input_polygon_map[input_index] = support_plane_idx; + m_sp2input_polygon[support_plane_idx].insert(input_index); + } + } + + template + void preprocess(std::vector& points, const FT min_dist = 0, const FT min_angle = FT(10)) const { + remove_equal_points(points, min_dist); + + remove_collinear_points(points, min_angle); + } + + template + void remove_equal_points(std::vector& points, const FT min_dist) const { + std::vector polygon; + const std::size_t n = points.size(); + for (std::size_t i = 0; i < n; ++i) { + const auto& first = points[i]; + polygon.push_back(first); + + while (true) { + const auto& p = points[i].first; + const std::size_t ip = (i + 1) % n; + const auto& q = points[ip].first; + const FT distance = from_exact(KSP::internal::distance(p, q)); + const bool is_small = (distance <= min_dist); + if (ip == 0 && is_small) break; + if (is_small) { + CGAL_assertion(ip != 0); + i = ip; continue; + } + CGAL_assertion(!is_small); + break; + }; + } + CGAL_assertion(polygon.size() >= 3); + points = polygon; + } + + template + void remove_collinear_points(std::vector& points, const FT min_angle) const { + std::vector polygon; + const std::size_t n = points.size(); + for (std::size_t i = 0; i < n; ++i) { + const std::size_t im = (i + n - 1) % n; + const std::size_t ip = (i + 1) % n; + + const auto& p = points[im].first; + const auto& q = points[i].first; + const auto& r = points[ip].first; + + Vector_2 vec1(q, r); + Vector_2 vec2(q, p); + vec1 = KSP::internal::normalize(vec1); + vec2 = KSP::internal::normalize(vec2); + + const Direction_2 dir1(vec1); + const Direction_2 dir2(vec2); + const FT angle = KSP::internal::angle_2(dir1, dir2); + + if (angle > min_angle) polygon.push_back(points[i]); + } + if (polygon.size() >= 3) points = polygon; + else remove_collinear_points(points, min_angle / FT(2)); + } + + template + void sort_points_by_direction(std::vector& points) const { + FT x = FT(0), y = FT(0); FT num = 0; + for (const auto& pair : points) { + const auto& point = pair.first; + x += point.x(); + y += point.y(); + num += 1; + } + x /= num; + y /= num; + const Point_2 mid(x, y); + + std::sort(points.begin(), points.end(), + [&](const Pair& a, const Pair& b) -> bool { + const Segment_2 sega(mid, a.first); + const Segment_2 segb(mid, b.first); + return ( Direction_2(sega) < Direction_2(segb) ); + }); + } + + /******************************* + ** PSimplices ** + ********************************/ + + const PVertices pvertices(const std::size_t support_plane_idx) const { + return PVertices( + boost::make_transform_iterator(mesh(support_plane_idx).vertices().begin(), Make_PSimplex(support_plane_idx)), + boost::make_transform_iterator(mesh(support_plane_idx).vertices().end(), Make_PSimplex(support_plane_idx))); + } + + const PEdges pedges(const std::size_t support_plane_idx) const { + return PEdges( + boost::make_transform_iterator(mesh(support_plane_idx).edges().begin(), Make_PSimplex(support_plane_idx)), + boost::make_transform_iterator(mesh(support_plane_idx).edges().end(), Make_PSimplex(support_plane_idx))); + } + + const PFaces pfaces(const std::size_t support_plane_idx) const { + return PFaces( + boost::make_transform_iterator(mesh(support_plane_idx).faces().begin(), Make_PSimplex(support_plane_idx)), + boost::make_transform_iterator(mesh(support_plane_idx).faces().end(), Make_PSimplex(support_plane_idx))); + } + + // Get prev and next pvertices of the free pvertex. + const PVertex prev(const PVertex& pvertex) const { + return PVertex(pvertex.first, support_plane(pvertex).prev(pvertex.second)); + } + const PVertex next(const PVertex& pvertex) const { + return PVertex(pvertex.first, support_plane(pvertex).next(pvertex.second)); + } + + void get_and_sort_all_connected_iedges(const std::size_t sp_idx, const IVertex& ivertex, std::vector< std::pair >& iedges) const { + auto inc_iedges = incident_iedges(ivertex); + const std::function lambda = + [&](const IEdge& inc_iedge) { + const auto iplanes = intersected_planes(inc_iedge); + if (iplanes.find(sp_idx) == iplanes.end()) { + return; + } + const Direction_2 direction( + point_2(sp_idx, opposite(inc_iedge, ivertex)) - + point_2(sp_idx, ivertex)); + iedges.push_back(std::make_pair(inc_iedge, direction)); + }; + + std::copy( + inc_iedges.begin(), inc_iedges.end(), + boost::make_function_output_iterator(lambda) + ); + + std::sort(iedges.begin(), iedges.end(), + [&](const std::pair& a, + const std::pair& b) -> bool { + return a.second < b.second; + } + ); + CGAL_assertion(iedges.size() > 0); + } + + const IFace add_iface(std::size_t support_plane) { + return m_intersection_graph.add_face(support_plane);; + } + + const PFace add_iface_to_mesh(std::size_t support_plane, IFace f_idx) { + typename Intersection_graph::Face_property &f = m_intersection_graph.face(f_idx); + + std::vector vertices; + vertices.reserve(f.vertices.size()); + Support_plane& sp = m_support_planes[support_plane]; + + for (auto v : f.vertices) { + auto& m = sp.ivertex2pvertex(); + std::pair p(v, Vertex_index()); + auto pair = m.insert(p); + if (pair.second) { + pair.first->second = sp.mesh().add_vertex(point_2(support_plane, v)); + } + sp.set_ivertex(pair.first->second, v); + vertices.push_back(pair.first->second); + } + + Face_index fi = sp.mesh().add_face(vertices); + if (fi == Support_plane::Mesh::null_face()) { + std::cout << "ERROR: invalid face created!" << std::endl; + for (std::size_t i = 0; i < f.vertices.size(); i++) { + std::cout << "2 " << point_3(f.vertices[i]) << " " << point_3(f.vertices[(i + 1) % f.vertices.size()]) << std::endl; + } + std::cout << "ERROR: end of invalid face" << std::endl; + } + + // Link pedges to iedges + auto h = sp.mesh().halfedge(fi); + auto first = h; + do { + Edge_index e = sp.mesh().edge(h); + PVertex t = PVertex(support_plane, sp.mesh().target(h)); + PVertex s = PVertex(support_plane, sp.mesh().source(h)); + IVertex it = ivertex(t); + IVertex is = ivertex(s); + sp.set_iedge(e, m_intersection_graph.edge(is, it)); + h = sp.mesh().next(h); + } while (h != first); + + f.part_of_partition = true; + + return PFace(support_plane, fi); + } + + void clear_pfaces(const std::size_t support_plane_idx) { + support_plane(support_plane_idx).clear_pfaces(); + } + + void clear_polygon_faces(const std::size_t support_plane_idx) { + Mesh& m = mesh(support_plane_idx); + for (const auto& fi : m.faces()) { + m.remove_face(fi); + } + for (const auto& ei : m.edges()) { + m.remove_edge(ei); + } + for (const auto& vi : m.vertices()) { + m.set_halfedge(vi, Halfedge_index()); + } + } + + PVertex opposite(const PEdge& pedge, const PVertex& pvertex) const { + if (mesh(pedge).target(mesh(pedge).halfedge(pedge.second)) == pvertex.second) { + return PVertex(pedge.first, mesh(pedge).source(mesh(pedge).halfedge(pedge.second))); + } + CGAL_assertion(mesh(pedge).source(mesh(pedge).halfedge(pedge.second)) == pvertex.second); + return PVertex(pedge.first, mesh(pedge).target(mesh(pedge).halfedge(pedge.second))); + } + + Point_3 centroid_of_pface(const PFace& pface) const { + const std::function unary_f = + [&](const PVertex& pvertex) -> Point_3 { + return point_3(pvertex); + }; + const std::vector polygon( + boost::make_transform_iterator(pvertices_of_pface(pface).begin(), unary_f), + boost::make_transform_iterator(pvertices_of_pface(pface).end(), unary_f)); + CGAL_assertion(polygon.size() >= 3); + return CGAL::centroid(polygon.begin(), polygon.end()); + } + + PEdges_of_pface pedges_of_pface(const PFace& pface) const { + const auto pedges = PEdges_of_pface( + boost::make_transform_iterator(halfedges_around_face(halfedge(pface.second, mesh(pface)), mesh(pface)).begin(), Halfedge_to_pedge(pface.first, mesh(pface))), + boost::make_transform_iterator(halfedges_around_face(halfedge(pface.second, mesh(pface)), mesh(pface)).end(), Halfedge_to_pedge(pface.first, mesh(pface)))); + CGAL_assertion(pedges.size() >= 3); + return pedges; + } + + PEdges_around_pvertex pedges_around_pvertex(const PVertex& pvertex) const { + const auto pedges = PEdges_around_pvertex( + boost::make_transform_iterator(halfedges_around_target(halfedge(pvertex.second, mesh(pvertex)), mesh(pvertex)).begin(), Halfedge_to_pedge(pvertex.first, mesh(pvertex))), + boost::make_transform_iterator(halfedges_around_target(halfedge(pvertex.second, mesh(pvertex)), mesh(pvertex)).end(), Halfedge_to_pedge(pvertex.first, mesh(pvertex)))); + CGAL_assertion(pedges.size() >= 2); + return pedges; + } + + PVertices_of_pface pvertices_of_pface(const PFace& pface) const { + const auto pvertices = PVertices_of_pface( + boost::make_transform_iterator(halfedges_around_face(halfedge(pface.second, mesh(pface)), mesh(pface)).begin(), Halfedge_to_pvertex(pface.first, mesh(pface))), + boost::make_transform_iterator(halfedges_around_face(halfedge(pface.second, mesh(pface)), mesh(pface)).end(), Halfedge_to_pvertex(pface.first, mesh(pface)))); + CGAL_assertion(pvertices.size() >= 3); + return pvertices; + } + + std::vector incident_volumes(const PFace& query_pface) const { + std::vector nvolumes; + for (const auto& volume : m_volumes) { + for (const auto& pface : volume.pfaces) { + if (pface == query_pface) nvolumes.push_back(volume); + } + } + return nvolumes; + } + + void incident_faces(const IEdge& query_iedge, std::vector& nfaces) const { + nfaces.clear(); + for (const auto plane_idx : intersected_planes(query_iedge)) { + for (const auto pedge : pedges(plane_idx)) { + if (iedge(pedge) == query_iedge) { + const auto& m = mesh(plane_idx); + const auto he = m.halfedge(pedge.second); + const auto op = m.opposite(he); + const auto face1 = m.face(he); + const auto face2 = m.face(op); + if (face1 != Support_plane::Mesh::null_face()) { + nfaces.push_back(PFace(plane_idx, face1)); + } + if (face2 != Support_plane::Mesh::null_face()) { + nfaces.push_back(PFace(plane_idx, face2)); + } + } + } + } + } + + const std::vector& input(const PFace& pface) const{ return support_plane(pface).input(pface.second); } + std::vector& input(const PFace& pface) { return support_plane(pface).input(pface.second); } + + const int& k(const std::size_t support_plane_idx) const { return support_plane(support_plane_idx).k(); } + int& k(const std::size_t support_plane_idx) { return support_plane(support_plane_idx).k(); } + + const Vector_2& direction(const PVertex& pvertex) const { return support_plane(pvertex).direction(pvertex.second); } + Vector_2& direction(const PVertex& pvertex) { return support_plane(pvertex).direction(pvertex.second); } + + const FT speed(const PVertex& pvertex) { return support_plane(pvertex).speed(pvertex.second); } + + /******************************* + ** ISimplices ** + ********************************/ + + static IVertex null_ivertex() { return Intersection_graph::null_ivertex(); } + static IEdge null_iedge() { return Intersection_graph::null_iedge(); } + + decltype(auto) ivertices() const { return m_intersection_graph.vertices(); } + decltype(auto) iedges() const { return m_intersection_graph.edges(); } + + std::size_t nb_intersection_lines() const { return m_intersection_graph.nb_lines(); } + std::size_t line_idx(const IEdge& iedge) const { return m_intersection_graph.line(iedge); } + std::size_t line_idx(const PVertex& pvertex) const { return line_idx(iedge(pvertex)); } + + const IVertex add_ivertex(const IkPoint_3& point, const std::set& support_planes_idx) { + std::vector vec_planes; + std::copy( + support_planes_idx.begin(), + support_planes_idx.end(), + std::back_inserter(vec_planes)); + const auto pair = m_intersection_graph.add_vertex(point, vec_planes); + const auto ivertex = pair.first; + return ivertex; + } + + void add_iedge(const std::set& support_planes_idx, std::vector& vertices) { + const auto source = m_intersection_graph.point_3(vertices.front()); + std::sort(vertices.begin(), vertices.end(), + [&](const IVertex& a, const IVertex& b) -> bool { + const auto ap = m_intersection_graph.point_3(a); + const auto bp = m_intersection_graph.point_3(b); + const auto sq_dist_a = CGAL::squared_distance(source, ap); + const auto sq_dist_b = CGAL::squared_distance(source, bp); + return (sq_dist_a < sq_dist_b); + } + ); + + typename Intersection_kernel::Line_3 line; + auto it = support_planes_idx.begin(); + CGAL_assertion_code(bool intersect =) intersection(m_support_planes[*it++].exact_plane(), m_support_planes[*it++].exact_plane(), line); + CGAL_assertion(intersect); + + std::size_t line_idx = m_intersection_graph.add_line(line); + for (std::size_t i = 0; i < vertices.size() - 1; ++i) { + + //CGAL_assertion(!is_zero_length_iedge(vertices[i], vertices[i + 1])); + const auto pair = m_intersection_graph.add_edge( + vertices[i], vertices[i + 1], support_planes_idx); + const auto iedge = pair.first; + CGAL_assertion(pair.second);// is inserted? + m_intersection_graph.set_line(iedge, line_idx); + + for (const auto support_plane_idx : support_planes_idx) { + support_plane(support_plane_idx).unique_iedges().insert(iedge); + } + } + } + + const IVertex source(const IEdge& edge) const { return m_intersection_graph.source(edge); } + const IVertex target(const IEdge& edge) const { return m_intersection_graph.target(edge); } + + const IVertex opposite(const IEdge& edge, const IVertex& ivertex) const { + const auto out = source(edge); + if (out == ivertex) { + return target(edge); + } + CGAL_assertion(target(edge) == ivertex); + return out; + } + + decltype(auto) incident_iedges(const IVertex& ivertex) const { + return m_intersection_graph.incident_edges(ivertex); + } + + const std::vector& iedges(const std::size_t support_plane_idx) const { + return support_plane(support_plane_idx).iedges(); + } + + std::vector& iedges(const std::size_t support_plane_idx) { + return support_plane(support_plane_idx).iedges(); + } + + const std::vector& ibboxes(const std::size_t support_plane_idx) const { + return support_plane(support_plane_idx).ibboxes(); + } + + std::vector& ibboxes(const std::size_t support_plane_idx) { + return support_plane(support_plane_idx).ibboxes(); + } + + const std::set& intersected_planes(const IEdge& iedge) const { + return m_intersection_graph.intersected_planes(iedge); + } + + const std::set intersected_planes(const IVertex& ivertex, const bool keep_bbox = true) const { + std::set out; + for (const auto &incident_iedge : incident_iedges(ivertex)) { + for (const auto &support_plane_idx : intersected_planes(incident_iedge)) { + if (!keep_bbox && support_plane_idx < 6) { + continue; + } + out.insert(support_plane_idx); + } + } + return out; + } + + bool is_zero_length_iedge(const IVertex& a, const IVertex& b) const { + const auto& p = m_intersection_graph.point_3(a); + const auto& q = m_intersection_graph.point_3(b); + return KSP::internal::distance(p, q) == 0; + } + + bool is_iedge(const IVertex& source, const IVertex& target) const { + return m_intersection_graph.is_edge(source, target); + } + + bool is_bbox_iedge(const IEdge& edge) const { + for (const auto support_plane_idx : m_intersection_graph.intersected_planes(edge)) { + if (support_plane_idx < 6) { + return true; + } + } + return false; + } + + /******************************* + ** STRINGS ** + ********************************/ + + inline const std::string str(const IEdge& iedge) const { + std::ostringstream oss; oss << "IEdge" << iedge; return oss.str(); + } + + inline const std::string lstr(const PEdge& pedge) const { + return "PEdge(" + std::to_string(pedge.first) + ":e" + std::to_string(pedge.second) + + ")[v" + std::to_string(source(pedge).second) + "->v" + std::to_string(target(pedge).second) + "]"; + } + + /******************************* + ** CONNECTIVITY ** + ********************************/ + + bool has_ivertex(const PVertex& pvertex) const { return support_plane(pvertex).has_ivertex(pvertex.second); } + IVertex ivertex(const PVertex& pvertex) const { return support_plane(pvertex).ivertex(pvertex.second); } + + bool has_iedge(const PVertex& pvertex) const { return support_plane(pvertex).has_iedge(pvertex.second); } + IEdge iedge(const PVertex& pvertex) const { return support_plane(pvertex).iedge(pvertex.second); } + + bool has_iedge(const PEdge& pedge) const { return support_plane(pedge).has_iedge(pedge.second); } + IEdge iedge(const PEdge& pedge) const { return support_plane(pedge).iedge(pedge.second); } + + /******************************* + ** CONVERSIONS ** + ********************************/ + + IkPoint_2 to_2d(const std::size_t support_plane_idx, const IVertex& ivertex) const { + return support_plane(support_plane_idx).to_2d(point_3(ivertex)); + } + + Segment_2 to_2d(const std::size_t support_plane_idx, const Segment_3& segment_3) const { + return support_plane(support_plane_idx).to_2d(segment_3); + } + +/* + IkSegment_2 to_2d(const std::size_t support_plane_idx, const IkSegment_3& segment_3) const { + return support_plane(support_plane_idx).to_2d(segment_3); + }*/ + + Point_2 to_2d(const std::size_t support_plane_idx, const Point_3& point_3) const { + return support_plane(support_plane_idx).to_2d(point_3); + } + +/* + IkPoint_2 to_2d(const std::size_t support_plane_idx, const IkPoint_3& point_3) const { + return support_plane(support_plane_idx).to_2d(point_3); + }*/ + + Point_2 point_2(const PVertex& pvertex) const { + return support_plane(pvertex).point_2(pvertex.second); + } + + Point_2 point_2(const std::size_t support_plane_idx, const IVertex& ivertex) const { + return support_plane(support_plane_idx).to_2d(from_exact(point_3(ivertex))); + } + + IkSegment_2 segment_2(const std::size_t support_plane_idx, const IEdge& iedge) const { + return support_plane(support_plane_idx).to_2d(segment_3(iedge)); + } + + Point_3 to_3d(const std::size_t support_plane_idx, const Point_2& point_2) const { + return support_plane(support_plane_idx).to_3d(point_2); + } + +/* + IkPoint_3 to_3d(const std::size_t support_plane_idx, const IkPoint_2& point_2) const { + return support_plane(support_plane_idx).to_3d(point_2); + }*/ + + Point_3 point_3(const PVertex& pvertex) const { + return support_plane(pvertex).point_3(pvertex.second); + } + + IkPoint_3 point_3(const IVertex& vertex) const { + return m_intersection_graph.point_3(vertex); + } + + Segment_3 segment_3(const PEdge& pedge) const { + return support_plane(pedge).segment_3(pedge.second); + } + + IkSegment_3 segment_3(const IEdge& edge) const { + return m_intersection_graph.segment_3(edge); + } + + /******************************* + ** CHECKING PROPERTIES ** + ********************************/ + + template + bool is_valid_polygon(const std::size_t sp_idx, const std::vector& points) const { + std::vector< std::pair > polygon; + polygon.reserve(points.size()); + for (const auto& pair : points) { + const auto& p = pair.first; + const auto q = m_support_planes[sp_idx].to_2d(p); + polygon.push_back(std::make_pair(q, true)); + } + CGAL_assertion(polygon.size() == points.size()); + + // const bool is_simple = support_plane(sp_idx).is_simple_polygon(polygon); + // const bool is_convex = support_plane(sp_idx).is_convex_polygon(polygon); + const bool is_valid = support_plane(sp_idx).is_valid_polygon(polygon); + + if (!is_valid) { + for (const auto& pair : polygon) { + std::cout << m_support_planes[sp_idx].to_3d(pair.first) << std::endl; + } + } + + // CGAL_assertion_msg(is_simple, "ERROR: POLYGON IS NOT SIMPLE!"); + // CGAL_assertion_msg(is_convex, "ERROR: POLYGON IS NOT CONVEX!"); + CGAL_assertion_msg(is_valid, "ERROR: POLYGON IS NOT VALID!"); + return is_valid; + } + + bool check_bbox() const { + for (std::size_t i = 0; i < 6; ++i) { + const auto pfaces = this->pfaces(i); + for (const auto pface : pfaces) { + for (const auto pvertex : pvertices_of_pface(pface)) { + if (!has_ivertex(pvertex)) { + std::cout << "debug pvertex: " << std::endl; + CGAL_assertion_msg(has_ivertex(pvertex), "ERROR: BBOX VERTEX IS MISSING AN IVERTEX!"); + return false; + } + } + for (const auto pedge : pedges_of_pface(pface)) { + if (!has_iedge(pedge)) { + std::cout << "debug pedge: " << std::endl; + CGAL_assertion_msg(has_iedge(pedge), "ERROR: BBOX EDGE IS MISSING AN IEDGE!"); + return false; + } + } + } + } + return true; + } + + bool check_interior() const { + for (std::size_t i = 6; i < number_of_support_planes(); ++i) { + const auto pfaces = this->pfaces(i); + for (const auto pface : pfaces) { + for (const auto pvertex : pvertices_of_pface(pface)) { + if (!has_ivertex(pvertex)) { + std::cout << "debug pvertex " << std::endl; + CGAL_assertion_msg(has_ivertex(pvertex), "ERROR: INTERIOR VERTEX IS MISSING AN IVERTEX!"); + return false; + } + } + for (const auto pedge : pedges_of_pface(pface)) { + if (!has_iedge(pedge)) { + std::cout << "debug pedge " << std::endl; + CGAL_assertion_msg(has_iedge(pedge), "ERROR: INTERIOR EDGE IS MISSING AN IEDGE!"); + return false; + } + } + } + } + return true; + } + + bool check_vertices() const { + bool success = true; + + for (const auto vertex : m_intersection_graph.vertices()) { + const auto nedges = m_intersection_graph.incident_edges(vertex); + if (nedges.size() <= 2) { + std::cout << "ERROR: CURRENT NUMBER OF EDGES = " << nedges.size() << std::endl; + CGAL_assertion_msg(nedges.size() > 2, + "ERROR: VERTEX MUST HAVE AT LEAST 3 NEIGHBORS!"); + success = false; + } + } + return success; + } + + bool check_edges() const { + bool success = true; + + std::vector nfaces; + for (const auto edge : m_intersection_graph.edges()) { + incident_faces(edge, nfaces); + if (nfaces.size() == 1) { + std::cout << "ERROR: CURRENT NUMBER OF FACES = " << nfaces.size() << std::endl; + std::cout << edge << std::endl; + std::cout << "PFace(" << nfaces[0].first << " " << nfaces[0].second << ")" << std::endl; + CGAL_assertion_msg(nfaces.size() != 1, + "ERROR: EDGE MUST HAVE 0 OR AT LEAST 2 NEIGHBORS!"); + success = false; + } + } + return success; + } + + bool check_faces() const { + bool success = true; + + for (std::size_t i = 0; i < number_of_support_planes(); ++i) { + const auto pfaces = this->pfaces(i); + for (const auto pface : pfaces) { + const auto nvolumes = incident_volumes(pface); + if (nvolumes.size() == 0 || nvolumes.size() > 2) { + std::cout << "ERROR: CURRENT NUMBER OF VOLUMES = " << nvolumes.size() << std::endl; + CGAL_assertion_msg(nvolumes.size() == 1 || nvolumes.size() == 2, + "ERROR: FACE MUST HAVE 1 OR 2 NEIGHBORS!"); + success = false; + } + } + } + + return success; + } + + bool is_volume_degenerate(const std::vector& pfaces) const { + for (const auto& pface : pfaces) { + const auto pedges = pedges_of_pface(pface); + const std::size_t n = pedges.size(); + + std::size_t count = 0; + for (const auto pedge : pedges) { + CGAL_assertion(has_iedge(pedge)); + const auto iedge = this->iedge(pedge); + const std::size_t num_found = find_adjacent_pfaces(pface, iedge, pfaces); + if (num_found == 1) ++count; + } + if (count != n) { + std::cout << "- current number of neighbors " << count << " != " << n << std::endl; + dump_info(*this, pface, *pedges.begin(), pfaces, ""); + return true; + } + } + return false; + } +}; + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_DATA_STRUCTURE_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Finalizer.h b/Kinetic_space_partition/include/CGAL/KSP_3/Finalizer.h new file mode 100644 index 00000000000..e913a50c119 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Finalizer.h @@ -0,0 +1,791 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_FINALIZER_H +#define CGAL_KSP_3_FINALIZER_H + +#include +#include +#include + +// Internal includes. +#include +#include +#include + +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Finalizer { + +public: + using Kernel = GeomTraits; + +private: + using Intersection_kernel = IntersectionKernel; + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + using Vector_2 = typename Kernel::Vector_2; + using Vector_3 = typename Kernel::Vector_3; + using Segment_3 = typename Kernel::Segment_3; + using Line_3 = typename Kernel::Line_3; + using Plane_3 = typename Kernel::Plane_3; + using Direction_2 = typename Kernel::Direction_2; + using Tetrahedron_3 = typename Kernel::Tetrahedron_3; + + using From_exact = CGAL::Cartesian_converter; + using To_exact = CGAL::Cartesian_converter; + + using Data_structure = CGAL::KSP_3::internal::Data_structure; + + using IVertex = typename Data_structure::IVertex; + using IEdge = typename Data_structure::IEdge; + + using PVertex = typename Data_structure::PVertex; + using PEdge = typename Data_structure::PEdge; + using PFace = typename Data_structure::PFace; + + using Support_plane = typename Data_structure::Support_plane; + using Intersection_graph = typename Data_structure::Intersection_graph; + using Volume_cell = typename Data_structure::Volume_cell; + + using Mesh = typename Data_structure::Mesh; + using Vertex_index = typename Data_structure::Vertex_index; + using Face_index = typename Data_structure::Face_index; + using Edge_index = typename Data_structure::Edge_index; + using Halfedge_index = typename Data_structure::Halfedge_index; + + using F_component_map = typename Mesh::template Property_map::faces_size_type>; + using E_constraint_map = typename Mesh::template Property_map; + + struct Vertex_info { + bool tagged; + PVertex pvertex; + IVertex ivertex; + Vertex_info() : + tagged(false), + pvertex(Data_structure::null_pvertex()), + ivertex(Data_structure::null_ivertex()) + { } + }; + + struct Face_info { + std::size_t index; + std::size_t input; + Face_info() : + index(static_cast(-1)), + input(static_cast(-1)) + { } + }; + + using Parameters = KSP::internal::Parameters_3; + +public: + Finalizer(Data_structure& data, const Parameters& parameters) : + m_data(data), m_parameters(parameters) + { } + + void create_polyhedra() { + if (m_parameters.debug) { + for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) { + dump_2d_surface_mesh(m_data, sp, m_data.prefix() + "after-partition-sp" + std::to_string(sp)); + } + } + + std::cout.precision(20); + CGAL_assertion(m_data.check_bbox()); + CGAL_assertion(m_data.check_interior()); + CGAL_assertion(m_data.check_vertices()); + CGAL_assertion(m_data.check_edges()); + + merge_facets_connected_components(); + + create_volumes(); + + if (m_parameters.debug) { + for (const auto& v : m_data.volumes()) + dump_volume(m_data, v.pfaces, "volumes/" + m_data.prefix() + std::to_string(v.index), true, v.index); + } + CGAL_assertion(m_data.check_faces()); + } + +private: + Data_structure& m_data; + const Parameters& m_parameters; + std::map>> m_edge_to_sorted_faces; + + /******************************* + ** EXTRACTING VOLUMES ** + ********************************/ + + void calculate_centroid(Volume_cell& volume) { + // First find a point in the interior of the volume cell. + FT x = 0, y = 0, z = 0; + FT num = 0; + for (const PVertex& v : volume.pvertices) { + Point_3 p = m_data.point_3(v); + x += p.x(); + y += p.y(); + z += p.z(); + num += 1; + } + Point_3 inside(x / num, y / num, z / num); + + // Now create a vector of tetrahedrons. + std::vector tets; + tets.reserve(volume.pvertices.size()); + + for (const PFace& f : volume.pfaces) { + // Orientation of the tetrahedron depends on the orientation of the support plane of the polygon. + Support_plane sp = m_data.support_plane(f.first); + Vector_3 n = sp.plane().orthogonal_vector(); + const Mesh& m = sp.mesh(); + Halfedge_index first = m.halfedge(f.second); + Point_3 p = m_data.point_3(PVertex(f.first, m.target(first))); + + bool positive_side = (inside - p) * n > 0; + + Halfedge_index h = m.next(first); + Point_3 a = m_data.point_3(PVertex(f.first, m.target(h))); + h = m.next(h); + do { + Point_3 b = m_data.point_3(PVertex(f.first, m.target(h))); + + if (positive_side) + tets.push_back(Tetrahedron_3(p, a, b, inside)); + else + tets.push_back(Tetrahedron_3(p, b, a, inside)); + + a = b; + h = m.next(h); + } while (h != first); + } + + volume.centroid = CGAL::centroid(tets.begin(), tets.end(), CGAL::Dimension_tag<3>()); + } + + void create_volumes() { + // Initialize an empty volume map. + auto& volumes = m_data.volumes();//std::vector + auto& map_volumes = m_data.pface_neighbors();//std::map + + volumes.clear(); + map_volumes.clear(); + for (std::size_t i = 0; i < m_data.number_of_support_planes(); ++i) { + const auto pfaces = m_data.pfaces(i); + for (const auto pface : pfaces) + map_volumes[pface] = std::make_pair(-1, -1); + } + + for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) { + for (auto pface : m_data.pfaces(sp)) { + segment_adjacent_volumes(pface, volumes, map_volumes); + } + } + + std::map& face2index = m_data.face_to_index(); + std::vector >& face2volumes = m_data.face_to_volumes(); + std::size_t num_faces = 0; + + // Adjust neighbor information in volumes + for (std::size_t i = 0; i < volumes.size(); i++) { + auto& v = volumes[i]; + v.index = i; + v.faces.resize(v.pfaces.size()); + for (std::size_t f = 0; f < volumes[i].pfaces.size(); f++) { + auto& pf = volumes[i].pfaces[f]; + auto it = face2index.find(pf); + if (it == face2index.end()) { + face2index[pf] = num_faces; + v.faces[f] = num_faces++; + } + else + v.faces[f] = it->second; + } + + if (face2volumes.size() < num_faces) + face2volumes.resize(num_faces, std::pair(-1, -1)); + + for (std::size_t j = 0; j < volumes[i].neighbors.size(); j++) { + auto& pair = map_volumes.at(volumes[i].pfaces[j]); + if (pair.second == -1) + pair.second = -static_cast(volumes[i].pfaces[j].first + 1); + volumes[i].neighbors[j] = (pair.first == static_cast(i)) ? pair.second : pair.first; + face2volumes[v.faces[j]] = pair; + } + } + + m_data.face_is_part_of_input_polygon().resize(num_faces); + for (const auto& p : face2index) + m_data.face_is_part_of_input_polygon()[p.second] = m_data.support_plane(p.first.first).is_initial(p.first.second); + + m_data.face_to_vertices().resize(num_faces); + m_data.face_to_support_plane().resize(num_faces); + + for (auto& volume : volumes) { + create_cell_pvertices(volume); + calculate_centroid(volume); + volume.pface_oriented_outwards.resize(volume.pfaces.size()); + for (std::size_t i = 0; i < volume.pfaces.size(); i++) { + PVertex vtx = *m_data.pvertices_of_pface(volume.pfaces[i]).begin(); + volume.pface_oriented_outwards[i] = ((m_data.point_3(vtx) - volume.centroid) * m_data.support_plane(volume.pfaces[i]).plane().orthogonal_vector() < 0); + } + } + + remove_collinear_vertices(); + } + + void segment_adjacent_volumes(const PFace& pface, std::vector& volumes, std::map >& map_volumes) { + + // Check whether this face is already part of one or two volumes + auto& pair = map_volumes.at(pface); + if (pair.first != -1 && pair.second != -1) return; + + const std::size_t uninitialized = static_cast(-1); + std::size_t volume_indices[] = { uninitialized, uninitialized }; + //std::size_t other[] = { static_cast(-1), static_cast(-1) }; + + // Start new volume cell + // First of pair is positive side, second is negative + if (pair.first == -1) { + volume_indices[0] = volumes.size(); + pair.first = static_cast(volumes.size()); + volumes.push_back(Volume_cell()); + volumes.back().add_pface(pface, pair.second); + } + else { + //other[0] = pair.first; + if (pface.first < 6) + // Thus for a bbox pair.second is always -1. Thus if pair.first is already set, there is nothing to do. + return; + } + + if (pair.second == -1 && pface.first >= 6) { + volume_indices[1] = volumes.size(); + pair.second = static_cast(volumes.size()); + volumes.push_back(Volume_cell()); + volumes.back().add_pface(pface, pair.first); + } + //else other[1] = pair.second; + + // 0 is queue on positive side, 1 is queue on negative side + std::queue > queue[2]; + + // Get neighbors with smallest dihedral angle + const auto pedges = m_data.pedges_of_pface(pface); + std::vector neighbor_faces, adjacent_faces; + for (const auto pedge : pedges) { + CGAL_assertion(m_data.has_iedge(pedge)); + + m_data.incident_faces(m_data.iedge(pedge), neighbor_faces); + + if (neighbor_faces.size() == 2) { + // If there is only one neighbor, the edge is on the edge of the bbox. + // Thus the only neighbor needs to be a bbox face. + PFace neighbor = (neighbor_faces[0] == pface) ? neighbor_faces[1] : neighbor_faces[0]; + CGAL_assertion(neighbor.first < 6 && pface.first < 6); + Oriented_side side = oriented_side(pface, neighbor); + Oriented_side inverse_side = oriented_side(neighbor, pface); + CGAL_assertion(side != COPLANAR && inverse_side != COPLANAR); + + if (side == ON_POSITIVE_SIDE && volume_indices[0] != uninitialized) { + if (associate(neighbor, volume_indices[0], inverse_side, volumes, map_volumes)) + queue[0].push(std::make_pair(neighbor, inverse_side)); + } + else if (side == ON_NEGATIVE_SIDE && volume_indices[1] != uninitialized) + if (associate(neighbor, volume_indices[1], inverse_side, volumes, map_volumes)) + queue[1].push(std::make_pair(neighbor, inverse_side)); + + continue; + } + + PFace positive_side, negative_side; + + find_adjacent_faces(pface, pedge, neighbor_faces, positive_side, negative_side); + CGAL_assertion(positive_side != negative_side); + + if (volume_indices[0] != uninitialized) { + Oriented_side inverse_side = (positive_side.first == pface.first) ? ON_POSITIVE_SIDE : oriented_side(positive_side, pface); + if (associate(positive_side, volume_indices[0], inverse_side, volumes, map_volumes)) + queue[0].push(std::make_pair(positive_side, inverse_side)); + } + + if (volume_indices[1] != uninitialized) { + Oriented_side inverse_side = (negative_side.first == pface.first) ? ON_NEGATIVE_SIDE : oriented_side(negative_side, pface); + if (associate(negative_side, volume_indices[1], inverse_side, volumes, map_volumes)) + queue[1].push(std::make_pair(negative_side, inverse_side)); + } + } + + // Propagate both queues if volumes on either side of the pface are not segmented. + for (std::size_t i = 0; i < 2; i++) { + if (volume_indices[i] != uninitialized) { + while (!queue[i].empty()) { + propagate_volume(queue[i], volume_indices[i], volumes, map_volumes); + } + } + } + } + + void propagate_volume(std::queue >& queue, std::size_t volume_index, std::vector& volumes, std::map >& map_volumes) { + PFace pface; + Oriented_side seed_side; + std::tie(pface, seed_side) = queue.front(); + queue.pop(); + + // Get neighbors with smallest dihedral angle + const auto pedges = m_data.pedges_of_pface(pface); + std::vector neighbor_faces, adjacent_faces; + for (const auto pedge : pedges) { + CGAL_assertion(m_data.has_iedge(pedge)); + m_data.incident_faces(m_data.iedge(pedge), neighbor_faces); + + if (neighbor_faces.size() == 2) { + // If there is only one neighbor, the edge is on the corner of the bbox. + // Thus the only neighbor needs to be a bbox face. + PFace neighbor = (neighbor_faces[0] == pface) ? neighbor_faces[1] : neighbor_faces[0]; + CGAL_assertion(neighbor.first < 6 && pface.first < 6); + CGAL_assertion(oriented_side(pface, neighbor) == seed_side); + + Oriented_side inverse_side = oriented_side(neighbor, pface); + + CGAL_assertion(inverse_side == ON_POSITIVE_SIDE); + + if (associate(neighbor, volume_index, inverse_side, volumes, map_volumes)) + queue.push(std::make_pair(neighbor, inverse_side)); + continue; + } + + PFace positive_side, negative_side; + + find_adjacent_faces(pface, pedge, neighbor_faces, positive_side, negative_side); + CGAL_assertion(positive_side != negative_side); + + if (seed_side == ON_POSITIVE_SIDE) { + Oriented_side inverse_side = (pface.first == positive_side.first) ? seed_side : oriented_side(positive_side, pface); + if (associate(positive_side, volume_index, inverse_side, volumes, map_volumes)) + queue.push(std::make_pair(positive_side, inverse_side)); + } + else { + Oriented_side inverse_side = (pface.first == negative_side.first) ? seed_side : oriented_side(negative_side, pface); + if (associate(negative_side, volume_index, inverse_side, volumes, map_volumes)) + queue.push(std::make_pair(negative_side, inverse_side)); + } + } + } + + bool associate(const PFace& pface, std::size_t volume_index, Oriented_side side, std::vector& volumes, std::map >& map_volumes) { + auto& pair = map_volumes.at(pface); + + CGAL_assertion(side != COPLANAR); + + if (side == ON_POSITIVE_SIDE) { + if (pair.first == static_cast(volume_index)) + return false; + + pair.first = static_cast(volume_index); + volumes[volume_index].add_pface(pface, pair.second); + return true; + } + else if (side == ON_NEGATIVE_SIDE) { + if (pair.second == static_cast(volume_index)) + return false; + + pair.second = static_cast(volume_index); + volumes[volume_index].add_pface(pface, pair.first); + return true; + } + + CGAL_assertion(false); + return false; + } + + IVertex non_collinear_vertex(const PFace& pface, const IEdge& iedge) const { + std::size_t edge_line = m_data.igraph().line(iedge); + + auto& sp = m_data.support_plane(pface.first); + auto& mesh = sp.mesh(); + auto first = mesh.halfedge(pface.second); + auto h = first; + std::size_t last_line = m_data.igraph().line(m_data.iedge(PEdge(pface.first, mesh.edge(first)))); + + do { + h = mesh.next(h); + std::size_t line = m_data.igraph().line(m_data.iedge(PEdge(pface.first, mesh.edge(h)))); + if (line != edge_line && last_line != edge_line) + return m_data.ivertex(PVertex(pface.first, mesh.source(h))); + + last_line = line; + } while (first != h); + + CGAL_assertion_msg(false, "ERROR: non collinear vertex not found in pface!"); + + return IVertex(); + } + + void find_adjacent_faces(const PFace& pface, const PEdge& pedge, const std::vector& neighbor_faces, PFace& positive_side, PFace& negative_side) { + CGAL_assertion(neighbor_faces.size() > 2); + + // for each face, find vertex that is not collinear with the edge + // sort around a reference face + + const Segment_3 segment = m_data.segment_3(pedge); + IEdge ie = m_data.iedge(pedge); + non_collinear_vertex(pface, ie); + + std::vector >& dir_edges = m_edge_to_sorted_faces[ie]; + if (dir_edges.empty()) { + typename Intersection_kernel::Point_3 source = m_data.point_3(m_data.igraph().source(ie)); + typename Intersection_kernel::Point_3 target = m_data.point_3(m_data.igraph().target(ie)); + typename Intersection_kernel::Point_3 reference = m_data.point_3(non_collinear_vertex(pface, ie)); + + dir_edges.push_back(std::make_pair(reference, pface)); + + // Get orientation towards edge of other faces + for (const PFace& face : neighbor_faces) { + if (face == pface) + continue; + + dir_edges.push_back(std::make_pair(m_data.point_3(non_collinear_vertex(face, ie)), face)); + } + + CGAL_assertion(dir_edges.size() == neighbor_faces.size()); + + // Sort directions + std::sort(dir_edges.begin(), dir_edges.end(), [&]( + const std::pair& p, + const std::pair& q) -> bool { + if (p.second == pface) + return true; + if (q.second == pface) + return false; + return Polygon_mesh_processing::Corefinement::sorted_around_edge(source, target, reference, p.first, q.first); + } + ); + } + + std::size_t n = dir_edges.size(); + for (std::size_t i = 0; i < n; ++i) { + if (dir_edges[i].second == pface) { + + const std::size_t im = (i + n - 1) % n; + const std::size_t ip = (i + 1) % n; + + // Check which side the faces are on + Orientation im_side = oriented_side(pface, dir_edges[im].second); + Orientation ip_side = oriented_side(pface, dir_edges[ip].second); + + //The angles decide where to push them, not necessarily the side. + //At least in case of a bbox corner intersected with a third plane breaks this. + + // Both on the negative side is not possible + CGAL_assertion(im_side != ON_NEGATIVE_SIDE || ip_side != ON_NEGATIVE_SIDE); + CGAL_assertion(im_side != COPLANAR || ip_side != COPLANAR); + + // If two are positive it has to be a bbox corner situation. + if (im_side == ON_POSITIVE_SIDE && ip_side == ON_POSITIVE_SIDE) { + CGAL_assertion(pface.first < 6); + if (dir_edges[im].second.first < 6) { + positive_side = dir_edges[ip].second; + negative_side = dir_edges[im].second; + } + else if (dir_edges[ip].second.first < 6) { + positive_side = dir_edges[im].second; + negative_side = dir_edges[ip].second; + } + else CGAL_assertion(false); + } + else if (ip_side == ON_POSITIVE_SIDE || im_side == ON_NEGATIVE_SIDE) { + positive_side = dir_edges[ip].second; + negative_side = dir_edges[im].second; + } + else { + positive_side = dir_edges[im].second; + negative_side = dir_edges[ip].second; + } + + return; + } + } + + CGAL_assertion_msg(false, "ERROR: NEXT PFACE IS NOT FOUND!"); + } + + Oriented_side oriented_side(const PFace& a, const PFace& b) const { + FT max_dist = 0; + if (a.first == b.first) + return CGAL::ON_ORIENTED_BOUNDARY; + Oriented_side side = CGAL::ON_ORIENTED_BOUNDARY; + const typename Intersection_kernel::Plane_3& p = m_data.support_plane(a.first).exact_plane(); + for (auto v : m_data.pvertices_of_pface(b)) { + side = p.oriented_side(m_data.point_3(m_data.ivertex(v))); + if (side != CGAL::ON_ORIENTED_BOUNDARY) + return side; + } + + return CGAL::ON_ORIENTED_BOUNDARY; + } + + void merge_facets_connected_components() { + // Purpose: merge facets between the same volumes. Every pair of volumes can have at most one contact polygon (which also has to be convex) + // Precondition: all volumes are convex, the contact area between each pair of volumes is empty or convex + std::vector edge_constraint_maps(m_data.number_of_support_planes()); + + for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) { + //dump_2d_surface_mesh(m_data, sp, "face_merge/" + m_data.prefix() + std::to_string(sp) + "-before"); + typename Support_plane::Mesh& mesh = m_data.support_plane(sp).mesh(); + + edge_constraint_maps[sp] = mesh.template add_property_map("e:keep", true).first; + F_component_map fcm = mesh.template add_property_map::faces_size_type>("f:component", 0).first; + + for (auto e : mesh.edges()) { + IEdge iedge = m_data.iedge(PEdge(sp, e)); + + if (is_occupied(iedge, sp)) + edge_constraint_maps[sp][e] = true; + else + edge_constraint_maps[sp][e] = false; + } + + CGAL::Polygon_mesh_processing::connected_components(mesh, fcm, CGAL::parameters::edge_is_constrained_map(edge_constraint_maps[sp])); + + merge_connected_components(sp, mesh, fcm, edge_constraint_maps[sp]); + + mesh.collect_garbage(); + } + } + + void merge_connected_components(std::size_t sp_idx, typename Support_plane::Mesh& mesh, F_component_map& fcm, E_constraint_map ecm) { + using Halfedge = typename Support_plane::Halfedge_index; + using Face = typename Support_plane::Face_index; + + std::vector initial_component; + std::size_t num_components = 0; + + for (const auto& f : mesh.faces()) + num_components = (std::max)(num_components, fcm[f]); + + initial_component.resize(num_components + 1, false); + Support_plane& sp = m_data.support_plane(sp_idx); + for (const auto& f : mesh.faces()) { + if (sp.is_initial(f)) + initial_component[fcm[f]] = true; + } + + //std::vector remove_edges; + std::vector remove_vertices(mesh.vertices().size(), true); + std::vector remove_faces(mesh.faces().size(), true); + + std::vector visited_halfedges(mesh.halfedges().size(), false); + for (auto h : mesh.halfedges()) { + Point_3 s = sp.to_3d(mesh.point(mesh.source(h))); + Point_3 t = sp.to_3d(mesh.point(mesh.target(h))); + std::vector pts; + pts.push_back(s); + pts.push_back(t); + if (visited_halfedges[h]) + continue; + + visited_halfedges[h] = true; + // Skip the outside edges. + if (mesh.face(h) == mesh.null_face()) + continue; + + Face f0 = mesh.face(h); + + typename boost::graph_traits::faces_size_type c0 = fcm[f0], c_other; + Face f_other = mesh.face(mesh.opposite(h)); + + // Check whether the edge is between different components. + if (f_other != mesh.null_face()) { + if (c0 == fcm[f_other]) { + continue; + } + } + + set_halfedge(f0, h, mesh); + remove_faces[f0] = false; + if (initial_component[c0]) + sp.set_initial(f0); + + // Find halfedge loop around component. + std::vector loop; + loop.push_back(h); + remove_vertices[mesh.target(h)] = false; + Halfedge first = h; + do { + Halfedge n = h; + //Point_3 tn = m_data.support_plane(sp).to_3d(mesh.point(mesh.target(h))); + + do { + if (n == h) + n = mesh.next(n); + else + n = mesh.next(mesh.opposite(n)); + + //Point_3 tn2 = m_data.support_plane(sp).to_3d(mesh.point(mesh.target(h))); + visited_halfedges[n] = true; + + //Face_index fn = mesh.face(n); + + f_other = mesh.face(mesh.opposite(n)); + if (f_other == mesh.null_face()) + break; + c_other = fcm[f_other]; + if (c0 == c_other && ecm[Edge_index(n >> 1)]) + std::cout << "edge and face constraint map inconsistent1" << std::endl; + + if (c0 != c_other && !ecm[Edge_index(n >> 1)]) + std::cout << "edge and face constraint map inconsistent2" << std::endl; + } while (c0 == c_other && n != h); + + if (n == h) { + // Should not happen. + std::cout << "Searching for next edge of connected component failed" << std::endl; + } + loop.push_back(n); + set_face(n, f0, mesh); + set_next(h, n, mesh); + set_halfedge(mesh.target(h), h, mesh); + remove_vertices[mesh.target(n)] = false; + h = n; + } while (h != first); + } + + // Remove all vertices in remove_vertices and all edges marked in constrained list + for (auto f : mesh.faces()) { + if (remove_faces[f]) + remove_face(f, mesh); + } + + for (auto e : mesh.edges()) { + // If edge is not marked as constrained it can be removed. + if (!ecm[e]) { + remove_edge(e, mesh); + } + } + + for (auto v : mesh.vertices()) { + if (remove_vertices[v]) + remove_vertex(v, mesh); + } + + if (!mesh.is_valid(true)) { + std::cout << "mesh is not valid after merging faces of sp " << sp_idx << std::endl; + } + } + + bool is_occupied(IEdge iedge, std::size_t sp) { + const std::set planes = m_data.intersected_planes(iedge); + for (std::size_t j : planes) { + if (sp == j) + continue; + + m_data.support_plane(j).mesh().is_valid(true); + + for (auto e2 : m_data.support_plane(j).mesh().edges()) { + if (iedge == m_data.iedge(PEdge(j, e2))) { + return true; + } + } + } + + return false; + } + + void create_cell_pvertices(Volume_cell& cell) { + From_exact from_exact; + std::vector& ivertex2vertex = m_data.ivertex_to_index(); + std::vector& vertices = m_data.vertices(); + std::vector& exact_vertices = m_data.exact_vertices(); + std::vector >& face2vertices = m_data.face_to_vertices(); + std::vector& face2sp = m_data.face_to_support_plane(); + cell.pvertices.clear(); + for (std::size_t f = 0; f < cell.pfaces.size(); f++) { + const auto& pface = cell.pfaces[f]; + bool face_filled = !face2vertices[cell.faces[f]].empty(); + + if (!face_filled) { + face2vertices[cell.faces[f]].reserve(m_data.pvertices_of_pface(pface).size()); + face2sp[cell.faces[f]] = pface.first; + } + + for (const auto pvertex : m_data.pvertices_of_pface(pface)) { + CGAL_assertion(m_data.has_ivertex(pvertex)); + cell.pvertices.insert(pvertex); + + IVertex ivertex = m_data.ivertex(pvertex); + if (ivertex2vertex[ivertex] == -1) { + ivertex2vertex[ivertex] = static_cast(vertices.size()); + if (!face_filled) + face2vertices[cell.faces[f]].push_back(vertices.size()); + else + std::cout << "Should not happen" << std::endl; + vertices.push_back(from_exact(m_data.point_3(ivertex))); + exact_vertices.push_back(m_data.point_3(ivertex)); + } + else if (!face_filled) + face2vertices[cell.faces[f]].push_back(ivertex2vertex[ivertex]); + } + } + } + + void remove_collinear_vertices() { + auto& vertices = m_data.face_to_vertices(); + std::vector coll(m_data.exact_vertices().size(), true); + std::unordered_map > vtx2face; + + for (std::size_t f = 0; f < vertices.size(); f++) { + for (std::size_t i = 0; i < vertices[f].size(); i++) { + if (!coll[vertices[f][i]]) + continue; + const typename Intersection_kernel::Point_3& a = m_data.exact_vertices()[vertices[f][(i - 1 + vertices[f].size()) % vertices[f].size()]]; + const typename Intersection_kernel::Point_3& b = m_data.exact_vertices()[vertices[f][i]]; + const typename Intersection_kernel::Point_3& c = m_data.exact_vertices()[vertices[f][(i + 1) % vertices[f].size()]]; + if (!CGAL::collinear(a, b, c)) + coll[vertices[f][i]] = false; + else + vtx2face[vertices[f][i]].push_back(f); + } + } + + for (std::size_t i = 0; i < coll.size(); i++) { + if (!coll[i]) + continue; + const auto& f = vtx2face[i]; + for (std::size_t j = 0; j < f.size(); j++) { + for (std::size_t v = 0; v < vertices[f[j]].size(); v++) { + if (vertices[f[j]][v] == i) { + vertices[f[j]].erase(vertices[f[j]].begin() + v); + break; + } + } + } + } + } +}; + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_FINALIZER_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Graphcut.h b/Kinetic_space_partition/include/CGAL/KSP_3/Graphcut.h new file mode 100644 index 00000000000..a1a7789fc1d --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Graphcut.h @@ -0,0 +1,181 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSR_3_GRAPHCUT_H +#define CGAL_KSR_3_GRAPHCUT_H + +// #include + +// CGAL includes. +#include +//#define CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE +#include +#include +#include +#include +#include +#include + +// Internal includes. +#include +#include +#include + +namespace CGAL { +namespace KSR_3 { + +#ifdef DOXYGEN_RUNNING +#else + + template + class Graphcut { + + public: + using Kernel = GeomTraits; + + using FT = typename Kernel::FT; + using Point_3 = typename Kernel::Point_3; + using Triangle_2 = typename Kernel::Triangle_2; + using Triangle_3 = typename Kernel::Triangle_3; + using Indices = std::vector; + + using Delaunay_2 = CGAL::Delaunay_triangulation_2; + using Delaunay_3 = CGAL::Delaunay_triangulation_3; + + Graphcut( + const FT lambda) : m_lambda(lambda) { } + + void solve(const std::vector >& edges, const std::vector& edge_weights, const std::vector > &cost_matrix, std::vector &labels) { + assert(edges.size() == edge_weights.size()); + assert(!cost_matrix.empty()); + labels.resize(cost_matrix[0].size()); + for (std::size_t i = 0; i < cost_matrix[0].size(); i++) { + // Verify quadratic size + assert(cost_matrix[0].size() == cost_matrix[1].size()); + labels[i] = (cost_matrix[0][i] > cost_matrix[1][0]) ? 1 : 0; + } + compute_graphcut(edges, edge_weights, cost_matrix, labels); + } + + private: + const FT m_lambda; + + double get_face_cost( + const FT face_prob, const FT face_weight) const { + + CGAL_assertion(face_prob >= FT(0) && face_prob <= FT(1)); + CGAL_assertion(face_weight >= FT(0) && face_weight <= FT(1)); + + const double weight = CGAL::to_double(face_weight); + const double value = (1.0 - CGAL::to_double(face_prob)); + return weight * value; + } + + void compute_graphcut( + const std::vector< std::pair >& edges, + const std::vector& edge_costs, + const std::vector< std::vector >& cost_matrix, + std::vector& labels) const { + std::vector tmp = labels; + + std::cout << std::endl << "beta" << m_lambda << std::endl; + + std::vector edge_costs_lambda(edge_costs.size()); + std::vector > cost_matrix_lambda(2); + + for (std::size_t i = 0; i < edge_costs.size(); i++) + edge_costs_lambda[i] = edge_costs[i] * m_lambda; + + for (std::size_t i = 0; i < cost_matrix.size(); i++) { + cost_matrix_lambda[i].resize(cost_matrix[i].size()); + for (std::size_t j = 0; j < cost_matrix[i].size(); j++) + cost_matrix_lambda[i][j] = cost_matrix[i][j] * (1.0 - m_lambda); + } + + + double min = 10000000000; + double max = -min; + double edge_sum = 0; + for (std::size_t i = 0; i < edge_costs.size(); i++) { + min = (std::min)(edge_costs[i], min); + max = (std::max)(edge_costs[i], max); + edge_sum += edge_costs[i] * m_lambda; + } + + std::cout << "edge costs" << std::endl; + std::cout << "sum: " << edge_sum << std::endl; + std::cout << "min: " << min << std::endl; + std::cout << "max: " << max << std::endl; + + min = 1000000000; + max = -min; + + std::size_t sum_inside = 0; + std::size_t sum_outside = 0; + + for (std::size_t i = 6; i < cost_matrix[0].size(); i++) { + sum_inside += cost_matrix[0][i]; + sum_outside += cost_matrix[1][i]; + min = (std::min)(cost_matrix[0][i], min); + min = (std::min)(cost_matrix[1][i], min); + max = (std::max)(cost_matrix[0][i], max); + max = (std::max)(cost_matrix[1][i], max); + } + + std::cout << "label costs" << std::endl; + std::cout << "min: " << min << std::endl; + std::cout << "max: " << max << std::endl; + std::cout << "sum inside: " << sum_inside << std::endl; + std::cout << "sum outside: " << sum_outside << std::endl; + + CGAL::alpha_expansion_graphcut(edges, edge_costs_lambda, cost_matrix_lambda, labels); + /* + CGAL::min_cut( + edges, edge_costs, cost_matrix, labels, CGAL::parameters::implementation_tag(CGAL::Alpha_expansion_MaxFlow_tag()));*/ + +/* + bool difference = false; + for (std::size_t i = 0; i < labels.size(); i++) { + if (tmp[i] != labels[i]) { + difference = true; + break; + } + } + + std::cout << "Labels changed: " << difference << std::endl;*/ + } + +/* + void apply_new_labels( + const std::vector& labels, + std::vector& volumes) const { + + CGAL_assertion((volumes.size() + 6) == labels.size()); + for (std::size_t i = 0; i < volumes.size(); ++i) { + const std::size_t label = labels[i + 6]; + auto& volume = volumes[i]; + + if (label == 0) { + volume.visibility = Visibility_label::INSIDE; + } else { + volume.visibility = Visibility_label::OUTSIDE; + } + } + }*/ + }; + +#endif //DOXYGEN_RUNNING + +} // KSR_3 +} // CGAL + +#endif // CGAL_KSR_3_GRAPHCUT_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Initializer.h b/Kinetic_space_partition/include/CGAL/KSP_3/Initializer.h new file mode 100644 index 00000000000..be34da2cb05 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Initializer.h @@ -0,0 +1,874 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_INITIALIZER_H +#define CGAL_KSP_3_INITIALIZER_H + +#include + +// CGAL includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Internal includes. +#include +#include +#include + +#include + +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Initializer { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionKernel; + +private: + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + using Vector_2 = typename Kernel::Vector_2; + using Segment_2 = typename Kernel::Segment_2; + using Segment_3 = typename Kernel::Segment_3; + using Line_2 = typename Kernel::Line_2; + using Transform_3 = CGAL::Aff_transformation_3; + using Direction_2 = typename Kernel::Direction_2; + + using Data_structure = KSP_3::internal::Data_structure; + using Support_plane = typename Data_structure::Support_plane; + using IEdge = typename Data_structure::IEdge; + using IFace = typename Data_structure::IFace; + using Face_property = typename Data_structure::Intersection_graph::Face_property; + using Intersection_graph = typename Data_structure::Intersection_graph; + using IEdge_set = typename Data_structure::IEdge_set; + + using IVertex = typename Data_structure::IVertex; + + using To_exact = CGAL::Cartesian_converter; + using From_exact = CGAL::Cartesian_converter; + + using Bbox_3 = CGAL::Bbox_3; + using OBB_traits = CGAL::Oriented_bounding_box_traits_3; + + using Parameters = KSP::internal::Parameters_3; + + using Timer = CGAL::Real_timer; + +public: + Initializer(std::vector >& input_polygons, Data_structure& data, const Parameters& parameters) : + m_input_polygons(input_polygons), m_data(data), m_parameters(parameters) + { } + + Initializer(std::vector >& input_polygons, std::vector& input_planes, Data_structure& data, const Parameters& parameters) : + m_input_polygons(input_polygons), m_input_planes(input_planes), m_data(data), m_parameters(parameters) + { } + + void initialize(const std::array& bbox, std::vector& input_polygons) { + Timer timer; + timer.reset(); + timer.start(); + + std::vector< std::vector > bbox_faces; + bounding_box_to_polygons(bbox, bbox_faces); + add_polygons(bbox_faces, input_polygons); + + m_data.igraph().finished_bbox(); + + if (m_parameters.verbose) + std::cout << "* intersecting input polygons ... "; + + // Fills in the ivertices on support plane intersections inside the bbox. + make_polygons_intersection_free(); + + // Generation of ifaces + create_ifaces(); + + // Splitting the input polygons along intersection lines. + initial_polygon_iedge_intersections(); + + create_bbox_meshes(); + + // Starting from here the intersection graph is const, it won't change anymore. + if (m_parameters.verbose) + std::cout << "done" << std::endl; + + if (m_parameters.debug) + KSP_3::internal::dump(m_data, m_data.prefix() + "intersected"); + + CGAL_assertion(m_data.check_bbox()); + //m_data.set_limit_lines(); + m_data.precompute_iedge_data(); + + m_data.initialization_done(); + + if (m_parameters.debug) { + for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) + dump_2d_surface_mesh(m_data, sp, m_data.prefix() + "before-partition-sp" + std::to_string(sp)); + } + + if (m_parameters.verbose) { + std::cout << "v: " << m_data.igraph().number_of_vertices() << " f: " << m_data.igraph().number_of_faces() << std::endl; + } + } + + void clear() { + // to be added + } + +private: + std::vector >& m_input_polygons; + std::vector& m_input_planes; + Data_structure& m_data; + const Parameters& m_parameters; + + void add_iface_from_iedge(std::size_t sp_idx, IEdge edge, IEdge next, bool cw) { + IVertex s = m_data.source(edge); + IVertex t = m_data.target(edge); + + IFace face_idx = m_data.add_iface(sp_idx); + Face_property& face = m_data.igraph().face(face_idx); + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(s))); + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(t))); + face.vertices.push_back(s); + face.vertices.push_back(t); + face.edges.push_back(edge); + m_data.igraph().add_face(sp_idx, edge, face_idx); + + face.edges.push_back(next); + m_data.igraph().add_face(sp_idx, next, face_idx); + + std::size_t iterations = 0; + + int dir = (cw) ? -1 : 1; + const std::size_t uninitialized = static_cast(-1); + std::size_t inext; + while (s != m_data.target(next) && iterations < 10000) { + face.vertices.push_back(m_data.target(next)); + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(m_data.target(next)))); + + IEdge enext, eprev; + get_prev_next(sp_idx, next, eprev, enext); + + std::vector > connected; + m_data.get_and_sort_all_connected_iedges(sp_idx, m_data.target(next), connected); + inext = uninitialized; + for (std::size_t idx = 0; idx < connected.size(); idx++) { + if (connected[idx].first == next) { + inext = (idx + dir + connected.size()) % connected.size(); + break; + } + } + CGAL_assertion(inext != uninitialized); + + next = connected[inext].first; + face.edges.push_back(next); + m_data.igraph().add_face(sp_idx, next, face_idx); + + iterations++; + } + + // Loop complete, connecting face with all edges. + for (IEdge edge : face.edges) { + m_data.support_plane(sp_idx).add_neighbor(edge, face_idx); + CGAL_assertion_code(IFace f1 = m_data.support_plane(sp_idx).iface(edge);) + CGAL_assertion_code(IFace f2 = m_data.support_plane(sp_idx).other(edge, f1);) + CGAL_assertion(f1 == face_idx || f2 == face_idx); + } + + std::vector pts; + pts.reserve(face.pts.size()); + for (auto p : face.pts) + pts.push_back(p); + + face.poly = Polygon_2(pts.begin(), pts.end()); + + if (face.poly.orientation() != CGAL::COUNTERCLOCKWISE) { + face.poly.reverse_orientation(); + std::reverse(face.pts.begin(), face.pts.end()); + std::reverse(face.vertices.begin(), face.vertices.end()); + std::reverse(face.edges.begin(), face.edges.end()); + } + + CGAL_assertion(face.poly.orientation() == CGAL::COUNTERCLOCKWISE); + CGAL_assertion(face.poly.is_convex()); + CGAL_assertion(face.poly.is_simple()); + } + + void get_prev_next(std::size_t sp_idx, IEdge edge, IEdge& prev, IEdge& next) { + CGAL_assertion(edge != Intersection_graph::null_iedge()); + CGAL_assertion(sp_idx != static_cast(-1)); + + std::vector > connected; + m_data.get_and_sort_all_connected_iedges(sp_idx, m_data.target(edge), connected); + //if (connected.size() <= 2) ivertex is on bbox edge + std::size_t inext = static_cast(-1), iprev = static_cast(-1); + for (std::size_t idx = 0; idx < connected.size(); idx++) { + if (connected[idx].first == edge) { + iprev = (idx - 1 + connected.size()) % connected.size(); + inext = (idx + 1) % connected.size(); + break; + } + } + + CGAL_assertion(inext != static_cast(-1)); + CGAL_assertion(iprev != static_cast(-1)); + prev = connected[iprev].first; + next = connected[inext].first; + } + + void create_ifaces() { + for (std::size_t sp_idx = 0; sp_idx < m_data.number_of_support_planes(); sp_idx++) { + const IEdge_set& uiedges = m_data.support_plane(sp_idx).unique_iedges(); + + // Special case bbox without splits + if (sp_idx < 6 && uiedges.size() == 4) { + // Get first edge + IEdge first = *uiedges.begin(); + IEdge edge = first; + IVertex s = m_data.source(edge); + IVertex t = m_data.target(edge); + + // Create single IFace for unsplit bbox face + IFace face_idx = m_data.add_iface(sp_idx); + Face_property& face = m_data.igraph().face(face_idx); + + // Add first edge, vertices and points to face properties + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(s))); + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(t))); + face.vertices.push_back(s); + face.vertices.push_back(t); + face.edges.push_back(edge); + + // Link edge and face + m_data.igraph().add_face(sp_idx, edge, face_idx); + + // Walk around bbox face + while (s != t) { + auto inc_iedges = m_data.incident_iedges(t); + for (auto next : inc_iedges) { + // Filter edges that are not in this bbox face + const auto iplanes = m_data.intersected_planes(next); + if (iplanes.find(sp_idx) == iplanes.end()) { + continue; + } + + // Skip current edge + if (edge == next) + continue; + + // The only left edge is the next one. + edge = next; + break; + } + t = (m_data.target(edge) == t) ? m_data.source(edge) : m_data.target(edge); + face.vertices.push_back(t); + face.pts.push_back(m_data.support_plane(sp_idx).to_2d(m_data.igraph().point_3(t))); + face.edges.push_back(edge); + m_data.igraph().add_face(sp_idx, edge, face_idx); + } + + // create polygon in proper order + } + + bool all_on_bbox = true; + for (auto edge : uiedges) { + bool on_edge = m_data.igraph().iedge_is_on_bbox(edge); + //if (m_data.igraph().iedge_is_on_bbox(edge)) + // continue; + // + //Note the number of bbox lines during creation and skip all those. + + // If non-bbox support plane is treated, skip all edges on bbox as they only have one face. + if (sp_idx >= 6 && on_edge) + continue; + + // If bbox support plane is treated, skip edges on bbox edge. + if (sp_idx < 6 && m_data.igraph().line_is_bbox_edge(m_data.line_idx(edge))) + continue; + + all_on_bbox = false; + + IFace n1 = m_data.support_plane(sp_idx).iface(edge); + IFace n2 = m_data.support_plane(sp_idx).other(edge, n1); + if (n1 != Intersection_graph::null_iface() && n2 != Intersection_graph::null_iface()) + continue; + + Face_property np1, np2; + if (n1 != Intersection_graph::null_iface()) + np1 = m_data.igraph().face(n1); + + if (n2 != Intersection_graph::null_iface()) + np2 = m_data.igraph().face(n2); + + IEdge next, prev; + get_prev_next(sp_idx, edge, prev, next); + + // Check if cw face already exists. + bool skip = false; + if (n1 != Intersection_graph::null_iface()) { + if (np1.is_part(edge, next)) + skip = true; + } + + if (!skip && n2 != Intersection_graph::null_iface()) { + if (np2.is_part(edge, next)) + skip = true; + } + + if (!skip) { + add_iface_from_iedge(sp_idx, edge, next, false); + } + + // Check if cw face already exists. + skip = false; + if (n1 != Intersection_graph::null_iface()) { + if (np1.is_part(edge, prev)) + skip = true; + } + + if (!skip && n2 != Intersection_graph::null_iface()) { + if (np2.is_part(edge, prev)) + skip = true; + } + + if (!skip) { + add_iface_from_iedge(sp_idx, edge, prev, true); + } + } + + // Special case if the input polygon only intersects with the bbox. + if (all_on_bbox) { + IEdge next, prev; + get_prev_next(sp_idx, *uiedges.begin(), prev, next); + add_iface_from_iedge(sp_idx, *uiedges.begin(), prev, true); + } + } + } + + void initial_polygon_iedge_intersections() { + To_exact to_exact; + From_exact from_exact; + + for (std::size_t sp_idx = 0; sp_idx < m_data.number_of_support_planes(); sp_idx++) { + bool polygons_assigned = false; + Support_plane& sp = m_data.support_plane(sp_idx); + if (sp.is_bbox()) + continue; + + sp.mesh().clear_without_removing_property_maps(); + + std::map > line2edges; + // Get all iedges, sort into lines and test intersection per line? + for (const IEdge& edge : sp.unique_iedges()) { + + if (m_data.is_bbox_iedge(edge)) + continue; + + std::size_t line = m_data.igraph().line(edge); + + line2edges[line].push_back(edge); + } + + for (auto pair : line2edges) { + // Get line + //Line_2 l(sp.to_2d(m_data.point_3(m_data.source(pair.second[0]))),sp.to_2d(m_data.point_3(m_data.target(pair.second[0])))); + + typename Intersection_kernel::Point_2 a(sp.to_2d(m_data.point_3(m_data.source(pair.second[0])))); + typename Intersection_kernel::Point_2 b(sp.to_2d(m_data.point_3(m_data.target(pair.second[0])))); + typename Intersection_kernel::Line_2 exact_line(a, b); + Line_2 l = from_exact(exact_line); + + typename Intersection_kernel::Vector_2 ldir = exact_line.to_vector(); + ldir = (typename Intersection_kernel::FT(1.0) / CGAL::approximate_sqrt(ldir * ldir)) * ldir; + Vector_2 dir = from_exact(ldir); + + std::vector crossing_polygon_segments; + std::vector crossing_iedges; + typename Intersection_kernel::FT emin = (std::numeric_limits::max)(); + typename Intersection_kernel::FT emax = -(std::numeric_limits::max)(); + FT min_speed = (std::numeric_limits::max)(), max_speed = -(std::numeric_limits::max)(); + + CGAL::Oriented_side last_side = l.oriented_side(sp.data().original_vertices.back()); + Point_2 minp, maxp; + typename Intersection_kernel::Point_2 eminp, emaxp; + + // Map polygon to line and get min&max projection + for (std::size_t v = 0; v < sp.data().original_vertices.size(); v++) { + const Point_2& p = sp.data().original_vertices[v]; + + CGAL::Oriented_side s = l.oriented_side(p); + if (last_side != s) { + // Fetch former point to add segment. + const Point_2& prev = sp.data().original_vertices[(v + sp.data().original_vertices.size() - 1) % sp.data().original_vertices.size()]; + const Vector_2 edge_dir = sp.original_edge_direction((v + sp.data().original_vertices.size() - 1) % sp.data().original_vertices.size(), v); + typename Intersection_kernel::Segment_2 seg(to_exact(prev), to_exact(p)); + const auto result = CGAL::intersection(seg, exact_line); + typename Intersection_kernel::Point_2 intersection; + + if (result && CGAL::assign(intersection, result)) { + typename Intersection_kernel::FT eproj = (intersection - exact_line.point()) * ldir; + //FT proj = to_inexact(eproj); + if (eproj < emin) { + eminp = intersection; + emin = eproj; + minp = from_exact(intersection); + //min = proj; + typename Intersection_kernel::FT p = dir * edge_dir; + assert(p != 0); + min_speed = CGAL::approximate_sqrt(edge_dir * edge_dir) / from_exact(p); + } + if (emax < eproj) { + emaxp = intersection; + emax = eproj; + maxp = from_exact(intersection); + //max = proj; + typename Intersection_kernel::FT p = dir * edge_dir; + assert(p != 0); + max_speed = CGAL::approximate_sqrt(edge_dir * edge_dir) / from_exact(p); + } + } + else std::cout << "crossing segment does not intersect line" << std::endl; + crossing_polygon_segments.push_back(seg); + } + + last_side = s; + } + + // Is there any intersection? + // As the polygon is convex there can only be one line segment on the inside of the polygon + if (emin < emax) { + m_data.support_plane(sp_idx).set_crossed_line(pair.first); + // Collect crossing edges by overlapping min/max barycentric coordinates on line + for (IEdge e : pair.second) { + std::pair faces; + m_data.igraph().get_faces(sp_idx, e, faces); + IVertex lower = m_data.source(e); + IVertex upper = m_data.target(e); + if (lower > upper) { + IVertex tmp = upper; + upper = lower; + lower = tmp; + } + typename Intersection_kernel::FT s = (sp.to_2d(m_data.point_3(lower)) - exact_line.point()) * ldir; + typename Intersection_kernel::FT t = (sp.to_2d(m_data.point_3(upper)) - exact_line.point()) * ldir; + + if (s < t) { + if (s < emax && emin < t) { + std::pair faces; + m_data.igraph().get_faces(sp_idx, e, faces); + + polygons_assigned = true; + + if (!m_data.igraph().face(faces.first).part_of_partition) { + auto pface = m_data.add_iface_to_mesh(sp_idx, faces.first); + sp.data().initial_ifaces.push_back(faces.first); + sp.set_initial(pface.second); + } + + if (!m_data.igraph().face(faces.second).part_of_partition) { + auto pface = m_data.add_iface_to_mesh(sp_idx, faces.second); + sp.data().initial_ifaces.push_back(faces.second); + sp.set_initial(pface.second); + } + + typename Intersection_graph::Kinetic_interval& kinetic_interval = m_data.igraph().kinetic_interval(e, sp_idx); + crossing_iedges.push_back(e); + if (emin > s) { + typename Intersection_kernel::FT bary_edge_exact = (emin - s) / (t - s); + FT bary_edge = from_exact((emin - s) / (t - s)); + CGAL_assertion(bary_edge_exact >= 0); + FT time = CGAL::abs(from_exact(s - emin) / min_speed); + kinetic_interval.push_back(std::pair(0, time)); // border barycentric coordinate + kinetic_interval.push_back(std::pair(bary_edge, 0)); + } + else { + kinetic_interval.push_back(std::pair(0, 0)); + } + + if (t > emax) { + typename Intersection_kernel::FT bary_edge_exact = (emax - s) / (t - s); + FT bary_edge = from_exact((emax - s) / (t - s)); + CGAL_assertion(0 <= bary_edge_exact && bary_edge_exact <= 1); + FT time = CGAL::abs(from_exact(emax - t) / max_speed); + kinetic_interval.push_back(std::pair(bary_edge, 0)); + kinetic_interval.push_back(std::pair(1, time)); // border barycentric coordinate + } + else + kinetic_interval.push_back(std::pair(1, 0)); + } + } + else if (t < emax && emin < s) { + std::pair faces; + m_data.igraph().get_faces(sp_idx, e, faces); + + polygons_assigned = true; + + if (!m_data.igraph().face(faces.first).part_of_partition) { + auto pface = m_data.add_iface_to_mesh(sp_idx, faces.first); + sp.data().initial_ifaces.push_back(faces.first); + sp.set_initial(pface.second); + } + + if (!m_data.igraph().face(faces.second).part_of_partition) { + auto pface = m_data.add_iface_to_mesh(sp_idx, faces.second); + sp.data().initial_ifaces.push_back(faces.second); + sp.set_initial(pface.second); + } + + typename Intersection_graph::Kinetic_interval& kinetic_interval = m_data.igraph().kinetic_interval(e, sp_idx); + crossing_iedges.push_back(e); + if (s > emax) { + typename Intersection_kernel::FT bary_edge_exact = (s - emax) / (s - t); + FT bary_edge = from_exact((s - emax) / (s - t)); + CGAL_assertion(0 <= bary_edge_exact && bary_edge_exact <= 1); + FT time = CGAL::abs(from_exact(emax - s) / max_speed); + kinetic_interval.push_back(std::pair(0, time)); // border barycentric coordinate + kinetic_interval.push_back(std::pair(bary_edge, 0)); + } + else + kinetic_interval.push_back(std::pair(0, 0)); + + if (emin > t) { + typename Intersection_kernel::FT bary_edge_exact = (s - emin) / (s - t); + FT bary_edge = from_exact(bary_edge_exact); + CGAL_assertion(0 <= bary_edge_exact && bary_edge_exact <= 1); + FT time = CGAL::abs(from_exact(t - emin) / min_speed); + kinetic_interval.push_back(std::pair(bary_edge, 0)); + kinetic_interval.push_back(std::pair(1, time)); // border barycentric coordinate + } + else + kinetic_interval.push_back(std::pair(1, 0)); + } + } + } + } + + // If no faces have been assigned, the input polygon lies completely inside a face. + // Every IFace is checked whether the polygon, or just a single vertex, lies inside. + // The implementation takes advantage of the IFace being convex. + if (!polygons_assigned) { + IFace face = IFace(-1); + for (auto& f : sp.ifaces()) { + Face_property& fp = m_data.igraph().face(f); + + typename Intersection_kernel::Point_2 p = to_exact(sp.data().centroid); + bool outside = false; + + // poly, vertices and edges in IFace are oriented ccw + for (std::size_t i = 0; i < fp.pts.size(); i++) { + typename Intersection_kernel::Vector_2 ts = fp.pts[(i + fp.pts.size() - 1) % fp.pts.size()] - p; + typename Intersection_kernel::Vector_2 tt = fp.pts[i] - p; + + bool ccw = (tt.x() * ts.y() - tt.y() * ts.x()) <= 0; + if (!ccw) { + outside = true; + break; + } + } + if (!outside) { + if (face == IFace(-1)) + face = f; + else { + std::cout << "Two faces found for " << sp_idx << " sp, f1 " << face << " f2 " << f << std::endl; + } + } + } + if (face != IFace(-1)) { + if (!m_data.igraph().face(face).part_of_partition) { + auto pface = m_data.add_iface_to_mesh(sp_idx, face); + sp.data().initial_ifaces.push_back(face); + sp.set_initial(pface.second); + } + } + else + std::cout << "No IFace found for sp " << sp_idx << std::endl; + } + } + } + + void bounding_box_to_polygons(const std::array& bbox, std::vector >& bbox_faces) const { + bbox_faces.clear(); + bbox_faces.reserve(6); + + bbox_faces.push_back({ bbox[0], bbox[1], bbox[2], bbox[3] }); // zmin + bbox_faces.push_back({ bbox[0], bbox[5], bbox[6], bbox[1] }); // ymin + bbox_faces.push_back({ bbox[1], bbox[6], bbox[7], bbox[2] }); // xmax + bbox_faces.push_back({ bbox[2], bbox[7], bbox[4], bbox[3] }); // ymax + bbox_faces.push_back({ bbox[3], bbox[4], bbox[5], bbox[0] }); // xmin + bbox_faces.push_back({ bbox[5], bbox[4], bbox[7], bbox[6] }); // zmax + CGAL_assertion(bbox_faces.size() == 6); + } + + void add_polygons(const std::vector >& bbox_faces, std::vector& input_polygons) { + add_bbox_faces(bbox_faces); + + // Filter input polygons + std::vector remove(input_polygons.size(), false); + for (std::size_t i = 0; i < 6; i++) + for (std::size_t j = 0; j < m_input_planes.size(); j++) + if (m_data.support_plane(i).exact_plane() == m_input_planes[j] || m_data.support_plane(i).exact_plane() == m_input_planes[j].opposite()) { + m_data.support_plane(i).set_input_polygon(j); + remove[j] = true; + } + + std::size_t write = 0; + for (std::size_t i = 0; i < input_polygons.size(); i++) + if (!remove[i]) { + m_input_polygons[write] = m_input_polygons[i]; + m_input_planes[write] = m_input_planes[i]; + input_polygons[write] = input_polygons[i]; + write++; + } + m_input_polygons.resize(write); + m_input_planes.resize(write); + input_polygons.resize(write); + add_input_polygons(); + } + + void add_bbox_faces(const std::vector< std::vector >& bbox_faces) { + for (const auto& bbox_face : bbox_faces) + m_data.add_bbox_polygon(bbox_face); + + CGAL_assertion(m_data.number_of_support_planes() == 6); + CGAL_assertion(m_data.ivertices().size() == 8); + CGAL_assertion(m_data.iedges().size() == 12); + + if (m_parameters.verbose) { + std::cout << "* inserted bbox faces: " << bbox_faces.size() << std::endl; + } + } + + void add_input_polygons() { + using Polygon_2 = std::vector; + using Indices = std::vector; + + std::map< std::size_t, std::pair > polygons; + preprocess_polygons(polygons); + + for (const auto& item : polygons) { + const std::size_t support_plane_idx = item.first; + const auto& pair = item.second; + const Polygon_2& polygon = pair.first; + const Indices& input_indices = pair.second; + m_data.add_input_polygon(support_plane_idx, input_indices, polygon); + m_data.support_plane(support_plane_idx).set_input_polygon(static_cast(item.first) - 6); + } + //dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons"); + + CGAL_assertion(m_data.number_of_support_planes() >= 6); + if (m_parameters.verbose) { + std::cout << "* provided input polygons: " << m_data.input_polygons().size() << std::endl; + std::cout << "* inserted input polygons: " << polygons.size() << std::endl; + } + } + + template + void convert_polygon(const std::size_t support_plane_idx, const PointRange& polygon_3, std::vector& polygon_2) { + polygon_2.clear(); + polygon_2.reserve(polygon_3.size()); + for (const auto& point : polygon_3) { + const Point_3 converted(static_cast(point.x()), static_cast(point.y()), static_cast(point.z())); + + polygon_2.push_back(m_data.support_plane(support_plane_idx).to_2d(converted)); + } + CGAL_assertion(polygon_2.size() == polygon_3.size()); + } + + void preprocess_polygons(std::map< std::size_t, std::pair, std::vector > >& polygons) { + std::size_t input_index = 0; + std::vector polygon_2; + std::vector input_indices; + for (std::size_t i = 0; i < m_input_polygons.size(); i++) { + bool is_added = true; + std::size_t support_plane_idx = std::size_t(-1); + std::tie(support_plane_idx, is_added) = m_data.add_support_plane(m_input_polygons[i], false, m_input_planes[i]); + CGAL_assertion(support_plane_idx != std::size_t(-1)); + convert_polygon(support_plane_idx, m_input_polygons[i], polygon_2); + + if (is_added) { + input_indices.clear(); + input_indices.push_back(input_index); + polygons[support_plane_idx] = std::make_pair(polygon_2, input_indices); + + } + else { + CGAL_assertion(polygons.find(support_plane_idx) != polygons.end()); + auto& pair = polygons.at(support_plane_idx); + auto& other_polygon = pair.first; + auto& other_indices = pair.second; + other_indices.push_back(input_index); + merge_polygons(support_plane_idx, polygon_2, other_polygon); + } + ++input_index; + } + } + + void merge_polygons(const std::size_t support_plane_idx, const std::vector& polygon_a, std::vector& polygon_b) { + const bool is_debug = false; + CGAL_assertion(support_plane_idx >= 6); + if (is_debug) { + std::cout << std::endl << "support plane idx: " << support_plane_idx << std::endl; + } + + // Add points from a to b. + auto& points = polygon_b; + for (const auto& point : polygon_a) { + points.push_back(point); + } + + // Create the merged polygon. + std::vector merged; + create_merged_polygon(points, merged); + + if (is_debug) { + std::cout << "merged polygon: " << std::endl; + for (std::size_t i = 0; i < merged.size(); ++i) { + const std::size_t ip = (i + 1) % merged.size(); + const auto& p = merged[i]; + const auto& q = merged[ip]; + std::cout << "2 " << + m_data.to_3d(support_plane_idx, p) << " " << + m_data.to_3d(support_plane_idx, q) << std::endl; + } + } + + // Update b with the new merged polygon. + polygon_b = merged; + } + + void create_merged_polygon(const std::vector& points, std::vector& merged) const { + merged.clear(); + + CGAL::convex_hull_2(points.begin(), points.end(), std::back_inserter(merged)); + + CGAL_assertion(merged.size() >= 3); + } + + void create_bbox_meshes() { + for (std::size_t i = 0; i < 6; i++) { + m_data.clear_pfaces(i); + std::set ifaces = m_data.support_plane(i).ifaces(); + + for (auto iface : ifaces) { + m_data.add_iface_to_mesh(i, iface); + } + } + } + + void make_polygons_intersection_free() { + // First, create all transverse intersection lines. + using Map_p2vv = std::map, std::pair >; + Map_p2vv map_p2vv; + + for (const auto ivertex : m_data.ivertices()) { + const auto key = m_data.intersected_planes(ivertex, false); + if (key.size() < 2) { + continue; + } + + const auto pair = map_p2vv.insert( + std::make_pair(key, std::make_pair(ivertex, IVertex()))); + const bool is_inserted = pair.second; + if (!is_inserted) { + pair.first->second.second = ivertex; + } + } + + // Then, intersect these lines to find internal intersection vertices. + using Pair_pv = std::pair< std::set, std::vector >; + std::vector todo; + for (auto it_a = map_p2vv.begin(); it_a != map_p2vv.end(); ++it_a) { + const auto& set_a = it_a->first; + + todo.push_back(std::make_pair(set_a, std::vector())); + auto& crossed_vertices = todo.back().second; + crossed_vertices.push_back(it_a->second.first); + + std::set> done; + for (auto it_b = map_p2vv.begin(); it_b != map_p2vv.end(); ++it_b) { + const auto& set_b = it_b->first; + + std::size_t common_plane_idx = std::size_t(-1); + const std::function lambda = + [&](const std::size_t idx) { + common_plane_idx = idx; + }; + + std::set_intersection( + set_a.begin(), set_a.end(), + set_b.begin(), set_b.end(), + boost::make_function_output_iterator(lambda) + ); + + if (common_plane_idx != std::size_t(-1)) { + auto union_set = set_a; + union_set.insert(set_b.begin(), set_b.end()); + if (!done.insert(union_set).second) { + continue; + } + + typename Intersection_kernel::Point_2 point; + typename Intersection_kernel::Segment_3 seg_a(m_data.point_3(it_a->second.first), m_data.point_3(it_a->second.second)); + typename Intersection_kernel::Segment_3 seg_b(m_data.point_3(it_b->second.first), m_data.point_3(it_b->second.second)); + if (!intersection(m_data.support_plane(common_plane_idx).to_2d(seg_a), m_data.support_plane(common_plane_idx).to_2d(seg_b), point)) + continue; + + crossed_vertices.push_back( + m_data.add_ivertex(m_data.support_plane(common_plane_idx).to_3d(point), union_set)); + } + } + crossed_vertices.push_back(it_a->second.second); + } + + for (auto& t : todo) { + m_data.add_iedge(t.first, t.second); + } + + return; + } + + template + inline bool intersection(const Type1& t1, const Type2& t2, ResultType& result) const { + + const auto inter = CGAL::intersection(t1, t2); + if (!inter) return false; + if (CGAL::assign(result, inter)) + return true; + + return false; + } +}; + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_INITIALIZER_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Intersection_graph.h b/Kinetic_space_partition/include/CGAL/KSP_3/Intersection_graph.h new file mode 100644 index 00000000000..e86d696bc0b --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Intersection_graph.h @@ -0,0 +1,436 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_INTERSECTION_GRAPH_H +#define CGAL_KSP_3_INTERSECTION_GRAPH_H + +#include + +// Boost includes. +#include + +// CGAL includes. +#include +#include + +// Internal includes. +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Intersection_graph { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionKernel; + + using IkFT = typename Intersection_kernel::FT; + using Point_2 = typename Intersection_kernel::Point_2; + using Point_3 = typename Intersection_kernel::Point_3; + using Segment_3 = typename Intersection_kernel::Segment_3; + using Line_3 = typename Intersection_kernel::Line_3; + using Polygon_2 = typename CGAL::Polygon_2; + + struct Vertex_property { + Point_3 point; + Vertex_property() {} + Vertex_property(const Point_3& point) : point(point) {} + }; + + using Kinetic_interval = std::vector >; + + struct Edge_property { + std::size_t line; + std::size_t order; + std::map > faces; // For each intersecting support plane there is one pair of adjacent faces (or less if the edge is on the bbox) + std::set planes; + std::set crossed; + std::map intervals; // Maps support plane index to the kinetic interval. std::pair is the barycentric coordinate and intersection time. + Edge_property() : line(std::size_t(-1)), order(edge_counter++) { } + + Edge_property(const Edge_property& e) = default; + + const Edge_property& operator=(const Edge_property& other) { + line = other.line; + // order = other.order; + faces = other.faces; + planes = other.planes; + crossed = other.crossed; + intervals = other.intervals; + + return *this; + } + private: + static std::size_t edge_counter; + }; + + using Kinetic_interval_iterator = typename std::map::const_iterator; + + using Graph = boost::adjacency_list< + boost::setS, boost::vecS, boost::undirectedS, + Vertex_property, Edge_property>; + + using Vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using Edge_descriptor = typename boost::graph_traits::edge_descriptor; + using Face_descriptor = std::size_t; + + struct lex { + bool operator()(const Edge_descriptor& a, const Edge_descriptor& b) const { + Edge_property* pa = (Edge_property*)a.get_property(); + Edge_property* pb = (Edge_property*)b.get_property(); + return pa->order < pb->order; + } + }; + + using IEdge_set = std::set; + + struct Face_property { + Face_property() : support_plane(static_cast(-1)), part_of_partition(false) {} + Face_property(std::size_t support_plane_idx) : support_plane(support_plane_idx), part_of_partition(false) {} + std::size_t support_plane; + bool part_of_partition; + CGAL::Polygon_2 poly; + std::vector pts; + std::vector edges; + std::vector vertices; + bool is_part(Edge_descriptor a, Edge_descriptor b) { + std::size_t aidx = std::size_t(-1); + for (std::size_t i = 0; i < edges.size(); i++) { + if (edges[i] == a) { + aidx = i; + break; + } + } + + if (aidx == std::size_t(-1)) + return false; + + if (edges[(aidx + 1) % edges.size()] == b || edges[(aidx + edges.size() - 1) % edges.size()] == b) + return true; + + return false; + } + }; + +private: + Graph m_graph; + std::vector m_lines; + std::size_t m_nb_lines_on_bbox; + std::map m_map_points; + std::map, Vertex_descriptor> m_map_vertices; + std::vector m_ifaces; + + std::vector m_initial_part_of_partition; + std::vector > m_initial_intervals; + std::vector > m_initial_crossed; + +public: + Intersection_graph() : + m_nb_lines_on_bbox(0) + { } + + void clear() { + m_graph.clear(); + m_map_points.clear(); + m_map_vertices.clear(); + } + + std::size_t number_of_vertices() const { + return static_cast(boost::num_vertices(m_graph)); + } + + std::size_t number_of_faces() const { + return m_ifaces.size(); + } + + static Vertex_descriptor null_ivertex() { + return boost::graph_traits::null_vertex(); + } + + static Edge_descriptor null_iedge() { + return Edge_descriptor(null_ivertex(), null_ivertex(), nullptr); + } + + static Face_descriptor null_iface() { + return std::size_t(-1); + } + + std::size_t add_line(const Line_3& line) { + m_lines.push_back(line); + return m_lines.size() - 1; + } + + std::size_t nb_lines() const { return m_lines.size(); } + + const std::pair add_vertex(const Point_3& point) { + const auto pair = m_map_points.insert(std::make_pair(point, Vertex_descriptor())); + const auto is_inserted = pair.second; + if (is_inserted) { + pair.first->second = boost::add_vertex(m_graph); + m_graph[pair.first->second].point = point; + } + return std::make_pair(pair.first->second, is_inserted); + } + + const std::pair add_vertex( + const Point_3& point, const std::vector& intersected_planes) { + const auto pair = m_map_vertices.insert(std::make_pair(intersected_planes, Vertex_descriptor())); + const auto is_inserted = pair.second; + if (is_inserted) { + pair.first->second = boost::add_vertex(m_graph); + m_graph[pair.first->second].point = point; + } + return std::make_pair(pair.first->second, is_inserted); + } + + const std::pair add_edge( + const Vertex_descriptor& source, const Vertex_descriptor& target, + const std::size_t support_plane_idx) { + const auto out = boost::add_edge(source, target, m_graph); + m_graph[out.first].planes.insert(support_plane_idx); + + return out; + } + + template + const std::pair add_edge( + const Vertex_descriptor& source, const Vertex_descriptor& target, + const IndexContainer& support_planes_idx) { + const auto out = boost::add_edge(source, target, m_graph); + for (const auto support_plane_idx : support_planes_idx) { + m_graph[out.first].planes.insert(support_plane_idx); + } + return out; + } + + const std::pair add_edge(const Point_3& source, const Point_3& target) { + return add_edge(add_vertex(source).first, add_vertex(target).first); + } + + std::size_t add_face(std::size_t support_plane_idx) { + m_ifaces.push_back(Face_property(support_plane_idx)); + return std::size_t(m_ifaces.size() - 1); + } + + bool add_face(std::size_t sp_idx, const Edge_descriptor& edge, const Face_descriptor& idx) { + auto pair = m_graph[edge].faces.insert(std::make_pair(sp_idx, std::pair(-1, -1))); + if (pair.first->second.first == static_cast(-1)) { + pair.first->second.first = idx; + return true; + } + else if (pair.first->second.second == static_cast(-1)) { + pair.first->second.second = idx; + return true; + } + return false; + } + + void get_faces(std::size_t sp_idx, const Edge_descriptor& edge, std::pair& pair) const { + auto it = m_graph[edge].faces.find(sp_idx); + if (it != m_graph[edge].faces.end()) + pair = it->second; + } + + const Face_property& face(Face_descriptor idx) const { + CGAL_assertion(idx < m_ifaces.size()); + return m_ifaces[idx]; + } + + Face_property& face(Face_descriptor idx) { + CGAL_assertion(idx < m_ifaces.size()); + return m_ifaces[idx]; + } + + const Edge_property& edge(Edge_descriptor idx) const { + return m_graph[idx]; + } + + void set_line(const Edge_descriptor& edge, const std::size_t line_idx) { + m_graph[edge].line = line_idx; + } + + std::size_t line(const Edge_descriptor& edge) const { + return m_graph[edge].line; + } + + const Line_3& line(std::size_t line_idx) const { + return m_lines[line_idx]; + } + + bool line_is_on_bbox(std::size_t line_idx) const { + return line_idx < m_nb_lines_on_bbox; + } + + bool line_is_bbox_edge(std::size_t line_idx) const { + return line_idx < 12; + } + + bool iedge_is_on_bbox(Edge_descriptor e) { + return line(e) < m_nb_lines_on_bbox; + } + + void finished_bbox() { + m_nb_lines_on_bbox = m_lines.size(); + } + + void initialization_done() { + auto e = edges(); + m_initial_crossed.resize(e.size()); + m_initial_intervals.resize(e.size()); + + std::size_t idx = 0; + for (const auto& edge : e) { + m_initial_intervals[idx] = m_graph[edge].intervals; + m_initial_crossed[idx++] = m_graph[edge].crossed; + } + + m_initial_part_of_partition.resize(m_ifaces.size()); + for (idx = 0; idx < m_ifaces.size(); idx++) + m_initial_part_of_partition[idx] = m_ifaces[idx].part_of_partition; + } + + void reset_to_initialization() { + auto e = edges(); + CGAL_assertion(e.size() == m_initial_crossed.size()); + CGAL_assertion(e.size() == m_initial_intervals.size()); + std::size_t idx = 0; + + for (auto edge : e) { + m_graph[edge].intervals = m_initial_intervals[idx]; + m_graph[edge].crossed = m_initial_crossed[idx++]; + } + + CGAL_assertion(m_ifaces.size() == m_initial_part_of_partition.size()); + for (idx = 0; idx < m_ifaces.size(); idx++) + m_ifaces[idx].part_of_partition = m_initial_part_of_partition[idx]; + } + + const std::pair + split_edge(const Edge_descriptor& edge, const Vertex_descriptor& vertex) { + + const auto source = boost::source(edge, m_graph); + const auto target = boost::target(edge, m_graph); + const auto prop = m_graph[edge]; + boost::remove_edge(edge, m_graph); + + bool is_inserted; + Edge_descriptor sedge; + std::tie(sedge, is_inserted) = boost::add_edge(source, vertex, m_graph); + if (!is_inserted) { + std::cerr << "WARNING: " << segment_3(edge) << " " << point_3(vertex) << std::endl; + } + CGAL_assertion(is_inserted); + m_graph[sedge] = prop; + + Edge_descriptor tedge; + std::tie(tedge, is_inserted) = boost::add_edge(vertex, target, m_graph); + if (!is_inserted) { + std::cerr << "WARNING: " << segment_3(edge) << " " << point_3(vertex) << std::endl; + } + CGAL_assertion(is_inserted); + m_graph[tedge] = prop; + + return std::make_pair(sedge, tedge); + } + + decltype(auto) vertices() const { + return CGAL::make_range(boost::vertices(m_graph)); + } + + decltype(auto) edges() const { + return CGAL::make_range(boost::edges(m_graph)); + } + + std::vector& faces() { + return m_ifaces; + } + + const std::vector& faces() const { + return m_ifaces; + } + + const Vertex_descriptor source(const Edge_descriptor& edge) const { + return boost::source(edge, m_graph); + } + + const Vertex_descriptor target(const Edge_descriptor& edge) const { + return boost::target(edge, m_graph); + } + + bool is_edge(const Vertex_descriptor& source, const Vertex_descriptor& target) const { + return boost::edge(source, target, m_graph).second; + } + + const Edge_descriptor edge(const Vertex_descriptor& source, const Vertex_descriptor& target) const { + return boost::edge(source, target, m_graph).first; + } + + decltype(auto) incident_edges(const Vertex_descriptor& vertex) const { + return CGAL::make_range(boost::out_edges(vertex, m_graph)); + } + + const std::set& intersected_planes(const Edge_descriptor& edge) const { + return m_graph[edge].planes; + } + + std::set& intersected_planes(const Edge_descriptor& edge) { + return m_graph[edge].planes; + } + + const std::pair kinetic_intervals(const Edge_descriptor& edge) { + return std::pair(m_graph[edge].intervals.begin(), m_graph[edge].intervals.end()); + } + Kinetic_interval& kinetic_interval(const Edge_descriptor& edge, std::size_t sp_idx) { + return m_graph[edge].intervals[sp_idx]; + } + + const Point_3& point_3(const Vertex_descriptor& vertex) const { + return m_graph[vertex].point; + } + + const Segment_3 segment_3(const Edge_descriptor& edge) const { + return Segment_3( + m_graph[boost::source(edge, m_graph)].point, + m_graph[boost::target(edge, m_graph)].point); + } + + const Line_3 line_3(const Edge_descriptor& edge) const { + return Line_3( + m_graph[boost::source(edge, m_graph)].point, + m_graph[boost::target(edge, m_graph)].point); + } + + bool has_crossed(const Edge_descriptor& edge, std::size_t sp_idx) { + return m_graph[edge].crossed.count(sp_idx) == 1; + } + + void set_crossed(const Edge_descriptor& edge, std::size_t sp_idx) { + CGAL_assertion(false); + m_graph[edge].crossed.insert(sp_idx); + } +}; + +template std::size_t Intersection_graph::Edge_property::edge_counter = 0; + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_INTERSECTION_GRAPH_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Propagation.h b/Kinetic_space_partition/include/CGAL/KSP_3/Propagation.h new file mode 100644 index 00000000000..26e9e228a8a --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Propagation.h @@ -0,0 +1,232 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_FACEPROPAGATION_H +#define CGAL_KSP_3_FACEPROPAGATION_H + +#include + +// Internal includes. +#include +#include +#include + +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Propagation { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionKernel; + +private: + using FT = typename Kernel::FT; + using IkFT = typename Intersection_kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Vector_2 = typename Kernel::Vector_2; + using Segment_2 = typename Kernel::Segment_2; + using Direction_2 = typename Kernel::Direction_2; + using Line_2 = typename Kernel::Line_2; + + using Data_structure = CGAL::KSP_3::internal::Data_structure; + + using IVertex = typename Data_structure::IVertex; + using IEdge = typename Data_structure::IEdge; + using IFace = typename Data_structure::IFace; + + using PVertex = typename Data_structure::PVertex; + using PEdge = typename Data_structure::PEdge; + using PFace = typename Data_structure::PFace; + + using Bbox_2 = CGAL::Bbox_2; + using Face_index = typename Data_structure::Face_index; + + using Parameters = KSP::internal::Parameters_3; + + using Face_event = typename Data_structure::Support_plane::Face_event; + + using From_exact = CGAL::Cartesian_converter; + + struct Face_event_order { + bool operator()(const Face_event& a, const Face_event& b) { + return a.time > b.time; + } + }; + +public: + Propagation(Data_structure& data, const Parameters& parameters) : + m_data(data), m_parameters(parameters), + m_min_time(-FT(1)), m_max_time(-FT(1)) + { } + + std::size_t propagate(std::size_t k) { + std::size_t num_events = 0; + m_data.reset_to_initialization(); + + for (std::size_t i = 0; i < m_data.number_of_support_planes(); ++i) + m_data.k(i) = static_cast(k); + + initialize_queue(); + + while (!m_face_queue.empty()) + run(num_events); + + return num_events; + } + + void clear() { + m_face_queue.clear(); + m_min_time = -FT(1); + m_max_time = -FT(1); + } + +private: + Data_structure& m_data; + const Parameters& m_parameters; + + FT m_min_time; + FT m_max_time; + + std::priority_queue, Face_event_order> m_face_queue; + + /******************************* + ** IDENTIFY EVENTS ** + ********************************/ + + void initialize_queue() { + m_data.fill_event_queue(m_face_queue); + } + + /******************************* + ** RUNNING ** + ********************************/ + + std::size_t run( + const std::size_t initial_iteration) { + + std::size_t iteration = initial_iteration; + while (!m_face_queue.empty()) { + // m_queue.print(); + + const Face_event event = m_face_queue.top(); + m_face_queue.pop(); + + ++iteration; + + apply(event); + } + return iteration; + } + + /******************************* + ** HANDLE EVENTS ** + ********************************/ + + void apply(const Face_event& event) { + if (m_data.igraph().face(event.face).part_of_partition) { + return; + } + + std::size_t line = m_data.line_idx(event.crossed_edge); + auto& sp = m_data.support_plane(event.support_plane); + int& k = sp.k(); + + const typename Data_structure::Intersection_graph::Face_property& face = m_data.igraph().face(event.face); + + From_exact from_exact; + Point_2 on_edge = sp.to_2d(from_exact(m_data.point_3(m_data.source(event.crossed_edge)))); + Point_2 center = from_exact(CGAL::centroid(face.pts.begin(), face.pts.end())); + Point_2 origin = sp.centroid(); + Vector_2 dir = sp.to_2d(from_exact(m_data.igraph().line(line).to_vector())); + dir = Vector_2(-dir.y(), dir.x()); // Vector orthogonal to line. + + bool need_check = false; + + // Only allow crossing edges away from the input polygon centroid. + if (((center - on_edge) * dir) * ((origin - on_edge) * dir) > 0) + need_check = true; + + if (need_check || !sp.has_crossed_line(line)) { + // Check intersection against kinetic intervals from other support planes + int crossing = 0; + auto kis = m_data.igraph().kinetic_intervals(event.crossed_edge); + for (auto ki = kis.first; ki != kis.second; ki++) { + if (ki->first == event.support_plane) + continue; + + for (std::size_t i = 0; i < ki->second.size(); i++) { + // Exactly on one + if (ki->second[i].first == event.intersection_bary) { + if (ki->second[i].second < event.time) { + crossing++; + } + + break; + } + + // Within an interval + if (ki->second[i].first > event.intersection_bary && ki->second[i - 1].first < event.intersection_bary) { + IkFT interval_pos = (event.intersection_bary - ki->second[i - 1].first) / (ki->second[i].first - ki->second[i - 1].first); + IkFT interval_time = interval_pos * (ki->second[i].second - ki->second[i - 1].second) + ki->second[i - 1].second; + + if (event.time > interval_time) { + crossing++; + } + + break; + } + } + } + + // Check if the k value is sufficient for crossing the edge. + if (k <= crossing) + return; + + // The edge can be crossed. + // Adjust k value + k -= crossing; + + m_data.support_plane(event.support_plane).set_crossed_line(line); + } + + // Associate IFace to mesh. + PFace f = m_data.add_iface_to_mesh(event.support_plane, event.face); + + // Calculate events for new border edges. + // Iterate inside of this face, check if each opposite edge is border and on bbox and then calculate intersection times. + std::vector border; + m_data.support_plane(event.support_plane).get_border(m_data.igraph(), f.second, border); + + for (IEdge edge : border) { + Face_event fe; + IkFT t = m_data.calculate_edge_intersection_time(event.support_plane, edge, fe); + if (t > 0) + m_face_queue.push(fe); + } + } +}; + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_FACEPROPAGATION_H diff --git a/Kinetic_space_partition/include/CGAL/KSP_3/Support_plane.h b/Kinetic_space_partition/include/CGAL/KSP_3/Support_plane.h new file mode 100644 index 00000000000..b1533072737 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/KSP_3/Support_plane.h @@ -0,0 +1,771 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KSP_3_SUPPORT_PLANE_H +#define CGAL_KSP_3_SUPPORT_PLANE_H + +#include + +// CGAL includes. +#include +#include + +// Internal includes. +#include +#include + +namespace CGAL { +namespace KSP_3 { +namespace internal { + +#ifdef DOXYGEN_RUNNING +#else + +template +class Support_plane { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionKernel; + using To_exact = CGAL::Cartesian_converter; + using From_exact = CGAL::Cartesian_converter; + + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + using Vector_2 = typename Kernel::Vector_2; + using Vector_3 = typename Kernel::Vector_3; + using Direction_2 = typename Kernel::Direction_2; + using Segment_2 = typename Kernel::Segment_2; + using Segment_3 = typename Kernel::Segment_3; + using Line_2 = typename Kernel::Line_2; + using Line_3 = typename Kernel::Line_3; + using Plane_3 = typename Kernel::Plane_3; + using Triangle_2 = typename Kernel::Triangle_2; + + using Mesh = CGAL::Surface_mesh; + using Intersection_graph = CGAL::KSP_3::internal::Intersection_graph; + using Bbox_2 = CGAL::Bbox_2; + + using IVertex = typename Intersection_graph::Vertex_descriptor; + using IEdge = typename Intersection_graph::Edge_descriptor; + using IFace = typename Intersection_graph::Face_descriptor; + + using IEdge_set = typename Intersection_graph::IEdge_set; + + using Vertex_index = typename Mesh::Vertex_index; + using Face_index = typename Mesh::Face_index; + using Edge_index = typename Mesh::Edge_index; + using Halfedge_index = typename Mesh::Halfedge_index; + + using V_vector_map = typename Mesh::template Property_map; + using V_ivertex_map = typename Mesh::template Property_map; + using V_iedge_map = typename Mesh::template Property_map; + using V_bool_map = typename Mesh::template Property_map; + using E_iedge_map = typename Mesh::template Property_map; + using F_index_map = typename Mesh::template Property_map >; + using F_uint_map = typename Mesh::template Property_map; + using F_bool_map = typename Mesh::template Property_map; + using V_original_map = typename Mesh::template Property_map; + using V_time_map = typename Mesh::template Property_map >; + + struct Face_event { + Face_event() {} + Face_event(std::size_t sp_idx, FT time, IEdge edge, IFace face) : support_plane(sp_idx), time(time), crossed_edge(edge), face(face) {} + std::size_t support_plane; + typename Intersection_kernel::FT time; + typename Intersection_kernel::FT intersection_bary; + IEdge crossed_edge; + IFace face; // The face that does not yet belong to the region. + }; + + struct Data { + Data() : mesh(), + v_ivertex_map(mesh.template add_property_map("v:ivertex", Intersection_graph::null_ivertex()).first), + v_iedge_map(mesh.template add_property_map("v:iedge", Intersection_graph::null_iedge()).first), + e_iedge_map(mesh.template add_property_map("e:iedge", Intersection_graph::null_iedge()).first), + input_map(mesh.template add_property_map >("f:input", std::vector()).first), + f_initial_map(mesh.template add_property_map("f:initial", false).first), + v_original_map(mesh.template add_property_map("v:original", false).first) {} + + bool is_bbox; + Point_2 centroid; + Plane_3 plane; + typename Intersection_kernel::Plane_3 exact_plane; + Mesh mesh; + + V_ivertex_map v_ivertex_map; + V_iedge_map v_iedge_map; + E_iedge_map e_iedge_map; + F_index_map input_map; + F_bool_map f_initial_map; + V_original_map v_original_map; + std::map > iedge2ifaces; + std::set ifaces; // All ifaces in the support plane + std::vector initial_ifaces; // IFaces which intersect with the input polygon and are thus part of the mesh before the propagation starts. + std::vector initial_pfaces; + std::map ivertex2pvertex; + IEdge_set unique_iedges; + std::set crossed_lines; + + std::vector iedges; + std::vector original_vertices; + std::vector original_vectors; + std::vector original_directions; + std::vector original_rays; + + FT distance_tolerance; + FT angle_tolerance; + + std::size_t actual_input_polygon; + + int k; + }; + +private: + static constexpr bool identical_kernel = !std::is_same_v; + + std::shared_ptr m_data; + +public: + Support_plane() : m_data(std::make_shared()) {} + + template + Support_plane(const PointRange& polygon, const bool is_bbox, typename Intersection_kernel::Plane_3 plane) : + m_data(std::make_shared()) { + + std::vector points; + points.reserve(polygon.size()); + for (const auto& point : polygon) { + points.push_back(Point_3( + static_cast(point.x()), + static_cast(point.y()), + static_cast(point.z()))); + } + CGAL_assertion(points.size() == polygon.size()); + + From_exact from_exact; + + m_data->k = 0; + m_data->plane = from_exact(plane); + m_data->exact_plane = plane; + m_data->is_bbox = is_bbox; + m_data->distance_tolerance = 0; + m_data->angle_tolerance = 0; + m_data->actual_input_polygon = static_cast(- 1); + + std::vector tris(points.size() - 2); + for (std::size_t i = 2; i < points.size(); i++) { + tris[i - 2] = Triangle_2(to_2d(points[0]), to_2d(points[i - 1]), to_2d(points[i])); + } + + m_data->centroid = CGAL::centroid(tris.begin(), tris.end(), CGAL::Dimension_tag<2>()); + + add_property_maps(); + } + + Support_plane(const std::vector& polygon, const bool is_bbox) : + m_data(std::make_shared()) { + + From_exact from_exact; + + std::vector points; + points.reserve(polygon.size()); + for (const auto& point : polygon) { + points.push_back(Point_3( + from_exact(point.x()), + from_exact(point.y()), + from_exact(point.z()))); + } + CGAL_assertion_code(const std::size_t n = points.size();) + CGAL_assertion(n == polygon.size()); + CGAL_assertion(n != 0); + + m_data->k = 0; + m_data->exact_plane = typename Intersection_kernel::Plane_3(polygon[0], polygon[1], polygon[2]); + m_data->plane = from_exact(m_data->exact_plane); + m_data->is_bbox = is_bbox; + m_data->distance_tolerance = 0; + m_data->angle_tolerance = 0; + m_data->actual_input_polygon = static_cast(- 1); + + std::vector tris(points.size() - 2); + for (std::size_t i = 2; i < points.size(); i++) { + tris[i - 2] = Triangle_2(to_2d(points[0]), to_2d(points[i - 1]), to_2d(points[i])); + } + + m_data->centroid = CGAL::centroid(tris.begin(), tris.end(), CGAL::Dimension_tag<2>()); + + add_property_maps(); + } + + void add_property_maps() { + + m_data->v_ivertex_map = m_data->mesh.template add_property_map("v:ivertex", Intersection_graph::null_ivertex()).first; + m_data->v_iedge_map = m_data->mesh.template add_property_map("v:iedge", Intersection_graph::null_iedge()).first; + m_data->e_iedge_map = m_data->mesh.template add_property_map("e:iedge", Intersection_graph::null_iedge()).first; + m_data->input_map = m_data->mesh.template add_property_map >("f:input", std::vector()).first; + m_data->v_original_map = m_data->mesh.template add_property_map("v:original", false).first; + m_data->f_initial_map = m_data->mesh.template add_property_map("f:initial", false).first; + } + + void link_property_maps() { + m_data->v_ivertex_map = m_data->mesh.template property_map("v:ivertex").value(); + m_data->v_iedge_map = m_data->mesh.template property_map("v:iedge").value(); + m_data->e_iedge_map = m_data->mesh.template property_map("e:iedge").value(); + m_data->input_map = m_data->mesh.template property_map >("f:input").value(); + m_data->v_original_map = m_data->mesh.template property_map("v:original").value(); + m_data->f_initial_map = m_data->mesh.template property_map("f:initial").value(); + } + + void centroid(Point_2& c) { + if (m_data->original_vertices.size() < 2) + return; + std::vector tris(m_data->original_vertices.size() - 2); + + for (std::size_t i = 2; i < m_data->original_vertices.size(); i++) { + tris[i - 2] = Triangle_2(m_data->original_vertices[0], m_data->original_vertices[i - 1], m_data->original_vertices[i]); + } + + c = CGAL::centroid(tris.begin(), tris.end(), CGAL::Dimension_tag<2>()); + } + + void get_border(Intersection_graph& igraph, std::vector& border) { + border.clear(); + auto m = mesh(); + + Vertex_index s = Mesh::null_vertex(); + + for (auto v : m_data->mesh.vertices()) { + if (m_data->mesh.is_border(v)) { + s = v; + break; + } + } + + if (s == Mesh::null_vertex()) { + std::cout << "Support plane does not have border vertices" << std::endl; + return; + } + + auto h = m.halfedge(s); + if (!m.is_border(h)) + h = m.opposite(h); + + auto n = h; + IVertex last = ivertex(s); + do { + n = m.next(n); + IVertex current = ivertex(m.target(n)); + border.push_back(igraph.edge(last, current)); + last = current; + } while (n != h && n != Mesh::null_halfedge()); + + if (n == Mesh::null_halfedge()) { + std::cout << " NULL_HALFEDGE!"; + } + //std::cout << "edges: " << border.size() << std::endl; + } + + void get_border(Intersection_graph& igraph, const Face_index& fi, std::vector& border) { + border.clear(); + auto m = mesh(); + + auto first = m.halfedge(fi); + auto h = first; + do { + auto o = m.opposite(h); + + if (m.is_border(o)) + border.push_back(igraph.edge(ivertex(m.target(h)), ivertex(m.target(o)))); + + h = m.next(h); + } while (h != first && h != Mesh::null_halfedge()); + + if (h == Mesh::null_halfedge()) { + std::cout << " NULL_HALFEDGE!"; + } + //std::cout << "edges: " << border.size() << std::endl; + } + + Data& data() { return *m_data; } + + FT distance_tolerance() const { + return m_data->distance_tolerance; + } + + FT angle_tolerance() const { + return m_data->angle_tolerance; + } + + void clear_pfaces() { + m_data->mesh.clear(); + add_property_maps(); + } + + const std::array + add_bbox_polygon( + const std::array& points, + const std::array& ivertices) { + + CGAL_assertion(CGAL::is_simple_2(points.begin(), points.end())); + CGAL_assertion(CGAL::is_convex_2(points.begin(), points.end())); + + std::array vertices; + for (std::size_t i = 0; i < 4; ++i) { + const auto vi = m_data->mesh.add_vertex(points[i]); + m_data->v_ivertex_map[vi] = ivertices[i]; + vertices[i] = vi; + } + + const auto fi = m_data->mesh.add_face(vertices); + CGAL_assertion(fi != Mesh::null_face()); + auto& input_vec = m_data->input_map[fi]; + CGAL_assertion(input_vec.empty()); + input_vec.push_back(std::size_t(-1)); + return vertices; + } + + template + std::size_t add_input_polygon( + const std::vector& points, + const std::vector& input_indices) { + + CGAL_assertion(is_simple_polygon(points)); + CGAL_assertion(is_convex_polygon(points)); + CGAL_assertion(is_valid_polygon(points)); + + To_exact to_exact; + + CGAL_assertion(points.size() >= 3); + std::vector tris(points.size() - 2); + for (std::size_t i = 2; i < points.size(); i++) + tris[i - 2] = Triangle_2(points[0].first, points[i - 1].first, points[i].first); + + m_data->centroid = CGAL::centroid(tris.begin(), tris.end(), CGAL::Dimension_tag<2>()); + + std::vector vertices; + const std::size_t n = points.size(); + CGAL_assertion(n >= 3); + vertices.reserve(n); + m_data->original_vertices.resize(n); + m_data->original_vectors.resize(n); + m_data->original_directions.resize(n); + m_data->original_rays.resize(n); + + FT sum_length = FT(0); + std::vector directions; + directions.reserve(n); + + std::vector > dir_vec; + + FT num = 0; + for (const auto& pair : points) { + const auto& point = pair.first; + directions.push_back(Vector_2(m_data->centroid, point)); + const FT length = static_cast( + CGAL::approximate_sqrt(CGAL::abs(directions.back() * directions.back()))); + sum_length += length; + num += 1; + } + CGAL_assertion(directions.size() == n); + sum_length /= num; + + dir_vec.reserve(n); + for (std::size_t i = 0; i < n; i++) + dir_vec.push_back(std::pair(i, directions[i])); + + std::sort(dir_vec.begin(), dir_vec.end(), + [&](const std::pair& a, + const std::pair& b) -> bool { + return a.second < b.second; + }); + + for (std::size_t i = 0; i < n; ++i) { + const auto& point = points[dir_vec[i].first].first; + const auto vi = m_data->mesh.add_vertex(point); + m_data->original_vertices[i] = point; + m_data->original_vectors[i] = directions[dir_vec[i].first] / sum_length; + m_data->original_directions[i] = Direction_2(directions[dir_vec[i].first]); + m_data->original_rays[i] = typename Intersection_kernel::Ray_2(to_exact(point), to_exact(m_data->original_vectors[i])); + m_data->v_original_map[vi] = true; + vertices.push_back(vi); + } + + for (std::size_t i = 0; i < m_data->original_directions.size(); i++) { + for (std::size_t j = 0; j < m_data->original_directions.size(); j++) { + if (j < i) + assert(m_data->original_directions[j] < m_data->original_directions[i]); + if (j > i) + assert(m_data->original_directions[i] < m_data->original_directions[j]); + } + } + + const auto fi = m_data->mesh.add_face(vertices); + CGAL_assertion(fi != Mesh::null_face()); + auto& input_vec = m_data->input_map[fi]; + CGAL_assertion(input_vec.empty()); + for (const std::size_t input_index : input_indices) { + input_vec.push_back(input_index); + } + return static_cast(fi); + } + + bool has_crossed_line(std::size_t line) const { + return m_data->crossed_lines.find(line) != m_data->crossed_lines.end(); + } + + void set_crossed_line(std::size_t line) { + m_data->crossed_lines.insert(line); + } + + void set_input_polygon(std::size_t input_polygon_idx) { + m_data->actual_input_polygon = input_polygon_idx; + } + + template + bool is_valid_polygon(const std::vector& polygon) const { + for (std::size_t i = 0; i < polygon.size(); ++i) { + const std::size_t ip = (i + 1) % polygon.size(); + const auto& p = polygon[i].first; + const auto& q = polygon[ip].first; + const bool is_equal_zero = (KSP::internal::distance(p, q) == 0); + CGAL_assertion_msg(!is_equal_zero, + "ERROR: WE HAVE EQUAL POINTS IN THE INPUT POLYGON!"); + if (is_equal_zero) return false; + } + return true; + } + + template + bool is_simple_polygon(const std::vector& points) const { + std::vector polygon; + polygon.reserve(points.size()); + for (const auto& pair : points) + polygon.push_back(pair.first); + CGAL_assertion(polygon.size() == points.size()); + return CGAL::is_simple_2(polygon.begin(), polygon.end()); + } + + template + bool is_convex_polygon(const std::vector& points) const { + std::vector polygon; + polygon.reserve(points.size()); + for (const auto& pair : points) + polygon.push_back(pair.first); + CGAL_assertion(polygon.size() == points.size()); + return CGAL::is_convex_2(polygon.begin(), polygon.end()); + } + + const Plane_3& plane() const { return m_data->plane; } + const typename Intersection_kernel::Plane_3& exact_plane() const { return m_data->exact_plane; } + const Point_2& centroid() const { return m_data->centroid; } + bool is_bbox() const { return m_data->is_bbox; } + std::map& ivertex2pvertex() { return m_data->ivertex2pvertex; } + + const Mesh& mesh() const { return m_data->mesh; } + Mesh& mesh() { return m_data->mesh; } + + const Point_2& get_point(const Vertex_index& vi) const { + return m_data->mesh.point(vi); + } + + void set_point(const Vertex_index& vi, const Point_2& point) { + m_data->mesh.point(vi) = point; + } + + void add_neighbor(IEdge edge, IFace face) { + std::pair> neighbor(edge, std::pair(face, Intersection_graph::null_iface())); + auto pair = m_data->iedge2ifaces.insert(neighbor); + m_data->ifaces.insert(face); + if (!pair.second) { + CGAL_assertion(pair.first->second.first != Intersection_graph::null_iface()); + CGAL_assertion(pair.first->second.second == Intersection_graph::null_iface()); + pair.first->second.second = face; + } + } + + IFace iface(IEdge edge) { + auto it = m_data->iedge2ifaces.find(edge); + if (it == m_data->iedge2ifaces.end()) + return Intersection_graph::null_iface(); + else return it->second.first; + } + + IFace other(IEdge edge, IFace face) { + auto it = m_data->iedge2ifaces.find(edge); + if (it == m_data->iedge2ifaces.end()) + return Intersection_graph::null_iface(); + if (it->second.first == face) + return it->second.second; + else + return it->second.first; + } + + std::size_t has_ifaces(IEdge edge) const { + auto it = m_data->iedge2ifaces.find(edge); + if (it == m_data->iedge2ifaces.end()) + return 0; + if (it->second.second != Intersection_graph::null_iface()) + return 2; + else + return 1; + } + + const Vertex_index prev(const Vertex_index& vi) const { + return m_data->mesh.source(m_data->mesh.halfedge(vi)); + } + const Vertex_index next(const Vertex_index& vi) const { + return m_data->mesh.target(m_data->mesh.next(m_data->mesh.halfedge(vi))); + } + + const Face_index face(const Vertex_index& vi) const { + + auto out = m_data->mesh.face(m_data->mesh.halfedge(vi)); + if (out == Face_index()) { + out = m_data->mesh.face(m_data->mesh.opposite(m_data->mesh.halfedge(vi))); + } + CGAL_assertion(out != Face_index()); + return out; + } + + const std::pair faces(const Vertex_index& vi) const { + + for (const auto& he : halfedges_around_target(halfedge(vi, m_data->mesh), m_data->mesh)) { + if (has_iedge(m_data->mesh.edge(he))) { + return std::make_pair( + m_data->mesh.face(he), m_data->mesh.face(m_data->mesh.opposite(he))); + } + } + CGAL_assertion_msg(false, "ERROR: NO CONSTRAINED EDGE FOUND!"); + return std::make_pair(Face_index(), Face_index()); + } + + const std::pair faces(const Halfedge_index& he) const { + + if (has_iedge(m_data->mesh.edge(he))) { + return std::make_pair( + m_data->mesh.face(he), m_data->mesh.face(m_data->mesh.opposite(he))); + } + CGAL_assertion_msg(false, "ERROR: NO CONSTRAINED EDGE FOUND!"); + return std::make_pair(Face_index(), Face_index()); + } + + const Point_2 point_2(const Vertex_index& vi) const { + return m_data->mesh.point(vi); + } + + const Point_3 point_3(const Vertex_index& vi) const { + return to_3d(m_data->mesh.point(vi)); + } + + const Segment_2 segment_2(const Edge_index& ei) const { + return Segment_2(m_data->mesh.point(m_data->mesh.source(m_data->mesh.halfedge(ei))), m_data->mesh.point(m_data->mesh.target(m_data->mesh.halfedge(ei)))); + } + + const Segment_3 segment_3(const Edge_index& ei) const { + return Segment_3( + point_3(m_data->mesh.source(m_data->mesh.halfedge(ei))), + point_3(m_data->mesh.target(m_data->mesh.halfedge(ei)))); + } + + void set_iedge( + const Vertex_index& v0, const Vertex_index& v1, const IEdge& iedge) const { + + const auto he = m_data->mesh.halfedge(v0, v1); + CGAL_assertion(he != Halfedge_index()); + const auto ei = m_data->mesh.edge(he); + m_data->e_iedge_map[ei] = iedge; + } + + void set_ivertex(const Vertex_index& vi, const IVertex& ivertex) const { + m_data->v_ivertex_map[vi] = ivertex; + } + + void set_iedge(const Vertex_index& vi, const IEdge& iedge) const { + m_data->v_iedge_map[vi] = iedge; + } + + void set_iedge(const Edge_index& ei, const IEdge& iedge) const { + m_data->e_iedge_map[ei] = iedge; + } + + const IEdge& iedge(const Edge_index& ei) const { + return m_data->e_iedge_map[ei]; + } + + const IEdge& iedge(const Vertex_index& vi) const { + return m_data->v_iedge_map[vi]; + } + + const IVertex& ivertex(const Vertex_index& vi) const { + return m_data->v_ivertex_map[vi]; + } + + bool has_iedge(const Edge_index& ei) const { + return (m_data->e_iedge_map[ei] != Intersection_graph::null_iedge()); + } + bool has_iedge(const Vertex_index& vi) const { + return (m_data->v_iedge_map[vi] != Intersection_graph::null_iedge()); + } + bool has_ivertex(const Vertex_index& vi) const { + return (m_data->v_ivertex_map[vi] != Intersection_graph::null_ivertex()); + } + + const Vector_2 original_edge_direction(std::size_t v1, std::size_t v2) const { + const Vector_2 edge = m_data->original_vertices[v1] - m_data->original_vertices[v2]; + Vector_2 orth = Vector_2(-edge.y(), edge.x()); + orth = (1.0 / (CGAL::approximate_sqrt(orth * orth))) * orth; + FT s1 = orth * m_data->original_vectors[v1]; + FT s2 = orth * m_data->original_vectors[v2]; + + if (abs(s1 - s2) > 0.0001) + std::cout << "edge speed seems inconsistent" << std::endl; + + return s1 * orth; + } + + const FT speed(const Vertex_index& vi) const { + return static_cast(CGAL::approximate_sqrt((CGAL::abs(m_data->direction[vi].squared_length())))); + } + + const std::vector& input(const Face_index& fi) const { return m_data->input_map[fi]; } + std::vector& input(const Face_index& fi) { return m_data->input_map[fi]; } + + bool is_original(const Vertex_index& vi) const { return m_data->v_original_map[vi]; } + + bool is_initial(const Face_index& fi) const { return m_data->f_initial_map[fi]; } + + void set_initial(const Face_index& fi) { m_data->f_initial_map[fi] = true; } + + const int& k() const { return m_data->k; } + int& k() { return m_data->k; } + + const std::set& ifaces() const { return m_data->ifaces; } + + const IEdge_set& unique_iedges() const { return m_data->unique_iedges; } + IEdge_set& unique_iedges() { return m_data->unique_iedges; } + + const std::vector& iedges() const { return m_data->iedges; } + std::vector& iedges() { return m_data->iedges; } + + const Point_2 to_2d(const Point_3& point) const { + return m_data->plane.to_2d(point); + } + + const Vector_2 to_2d(const Vector_3& vec) const { + return Vector_2( + m_data->plane.to_2d(Point_3(0, 0, 0)), + m_data->plane.to_2d(Point_3(0, 0, 0) + vec)); + } + + template::type > + const typename Intersection_kernel::Point_2 to_2d(const typename Intersection_kernel::Point_3& point) const { + return m_data->exact_plane.to_2d(point); + } + + const Line_2 to_2d(const Line_3& line) const { + return Line_2( + m_data->plane.to_2d(line.point()), + m_data->plane.to_2d(line.point() + line.to_vector())); + } + + template::type > + const typename Intersection_kernel::Line_2 to_2d(const typename Intersection_kernel::Line_3& line) const { + return typename Intersection_kernel::Line_2( + m_data->exact_plane.to_2d(line.point()), + m_data->exact_plane.to_2d(line.point() + line.to_vector())); + } + + const Segment_2 to_2d(const Segment_3& segment) const { + return Segment_2( + m_data->plane.to_2d(segment.source()), + m_data->plane.to_2d(segment.target())); + } + + template::type > + const typename Intersection_kernel::Segment_2 to_2d(const typename Intersection_kernel::Segment_3& segment) const { + return typename Intersection_kernel::Segment_2( + m_data->exact_plane.to_2d(segment.source()), + m_data->exact_plane.to_2d(segment.target())); + } + + const Vector_3 to_3d(const Vector_2& vec) const { + return Vector_3( + m_data->plane.to_3d(Point_2(FT(0), FT(0))), + m_data->plane.to_3d(Point_2(FT(0), FT(0)) + vec)); + } + + const Point_3 to_3d(const Point_2& point) const { + return m_data->plane.to_3d(point); + } + + template::type > + const typename Intersection_kernel::Point_3 to_3d(const typename Intersection_kernel::Point_2& point) const { + return m_data->exact_plane.to_3d(point); + } + + const Edge_index edge(const Vertex_index& v0, const Vertex_index& v1) { + return m_data->mesh.edge(m_data->mesh.halfedge(v0, v1)); + } + + const Edge_index add_edge( + const Vertex_index& v0, const Vertex_index& v1, const IEdge& iedge) { + + const auto out = m_data->mesh.edge(m_data->mesh.add_edge(v0, v1)); + m_data->e_iedge_map[out] = iedge; + return out; + } + + const Vertex_index add_vertex(const Point_2& point) { + return m_data->mesh.add_vertex(point); + } + + void remove_vertex(const Vertex_index& vi) { + m_data->mesh.remove_vertex(vi); + } + + const Edge_index split_vertex(const Vertex_index& vi) { + return m_data->mesh.edge( + CGAL::Euler::split_vertex( + m_data->mesh.halfedge(vi), + m_data->mesh.opposite(m_data->mesh.next(m_data->mesh.halfedge(vi))), + m_data->mesh)); + } + + const Vertex_index split_edge( + const Vertex_index& v0, const Vertex_index& v1) { + + return m_data->mesh.target( + CGAL::Euler::split_edge(m_data->mesh.halfedge(v0, v1), m_data->mesh)); + } +}; + +template +bool operator==(const Support_plane& a, const Support_plane& b) { + + if (a.is_bbox() || b.is_bbox()) { + return false; + } + + if (a.exact_plane() == b.exact_plane()) + return true; + else return false; +} + +#endif //DOXYGEN_RUNNING + +} // namespace internal +} // namespace KSP_3 +} // namespace CGAL + +#endif // CGAL_KSP_3_SUPPORT_LINE_H diff --git a/Kinetic_space_partition/include/CGAL/Kinetic_space_partition_3.h b/Kinetic_space_partition/include/CGAL/Kinetic_space_partition_3.h new file mode 100644 index 00000000000..e2bd11335c7 --- /dev/null +++ b/Kinetic_space_partition/include/CGAL/Kinetic_space_partition_3.h @@ -0,0 +1,2404 @@ +// Copyright (c) 2023 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sven Oesau, Florent Lafarge, Dmitry Anisimov, Simon Giraudot + +#ifndef CGAL_KINETIC_SPACE_PARTITION_3_H +#define CGAL_KINETIC_SPACE_PARTITION_3_H + +#include + +// Boost includes. +#include +#include + +#include +#include + +// CGAL includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Internal includes. +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace CGAL { + +/*! +* \ingroup PkgKineticSpacePartitionRef + \brief creates the kinetic partition of the bounding box of the polygons given as input data. The kinetic partition can either be initialized + by using the default constructor \link CGAL::Kinetic_space_partition_3::Kinetic_space_partition_3() `Kinetic_space_partition_3()`\endlink, `insert()` to provide input data and `initialize()` to prepare the partition or by using the constructor with input parameters. + + \tparam GeomTraits + must be a model of `KineticSpacePartitionTraits_3`. + + \tparam IntersectionTraits + must be a model of `Kernel` using exact computations. Defaults to `CGAL::Exact_predicates_exact_constructions_kernel`. +*/ +template +class Kinetic_space_partition_3 { + +public: + using Kernel = GeomTraits; + using Intersection_kernel = IntersectionTraits; + + using Point_3 = typename Kernel::Point_3; + + using Index = std::pair; + + /*! + identifies the support of a face in the exported linear cell complex, which is either an input polygon, identified by a non-negative number, a side of the bounding box in the rotated coordinate system or a face of the octree used to partition the scene. + */ + enum Face_support : int { + ZMIN = -1, + YMIN = -2, + XMAX = -3, + YMAX = -4, + XMIN = -5, + ZMAX = -6, + OCTREE_FACE = -7, + }; + + /*! + \brief this class provides a minimal model of `KineticLCCItems`. It adds attributes to faces and volumes and defines the use of index-based `LinearCellComplex`. + */ + class Linear_cell_complex_min_items { + public: + typedef CGAL::Tag_true Use_index; + typedef std::uint32_t Index_type; + + struct Face_attribute { + Face_support input_polygon_index; // Non-negative numbers represent the index of the input polygon. Negative numbers correspond to the values defined in the enum `Face_support`. + typename Intersection_kernel::Plane_3 plane; + bool part_of_initial_polygon; + }; + + struct Volume_attribute { + typename Intersection_kernel::Point_3 barycenter; + std::size_t volume_id; + }; + + template + struct Dart_wrapper { + typedef CGAL::Cell_attribute_with_point< LCC, void > Vertex_cell_attribute; + typedef CGAL::Cell_attribute< LCC, Face_attribute > Face_cell_attribute; + typedef CGAL::Cell_attribute< LCC, Volume_attribute > Volume_cell_attribute; + + typedef std::tuple Attributes; + }; + }; + +private: + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Vector_2 = typename Kernel::Vector_2; + using Vector_3 = typename Kernel::Vector_3; + using Plane_3 = typename Kernel::Plane_3; + using Line_3 = typename Kernel::Line_3; + using Line_2 = typename Kernel::Line_2; + using Triangle_2 = typename Kernel::Triangle_2; + using Transform_3 = CGAL::Aff_transformation_3; + + using Data_structure = KSP_3::internal::Data_structure; + + using IVertex = typename Data_structure::IVertex; + using IEdge = typename Data_structure::IEdge; + + using From_exact = typename CGAL::Cartesian_converter; + using To_exact = typename CGAL::Cartesian_converter; + + using Initializer = KSP_3::internal::Initializer; + using Propagation = KSP_3::internal::Propagation; + using Finalizer = KSP_3::internal::Finalizer; + + using Polygon_mesh = CGAL::Surface_mesh; + using Timer = CGAL::Real_timer; + using Parameters = KSP::internal::Parameters_3; + + using Octree = CGAL::Orthtree >; + using Octree_node = typename Octree::Node_index; + + struct VI + { + VI() + : idA2(-1, -1), idB2(-1, -1), input(false) + {} + + void set_point(const typename Intersection_kernel::Point_3& p) { + point_3 = p; + input = true; + } + + typename Intersection_kernel::Point_3 point_3; + std::set adjacent; + Index idA2, idB2; + bool input; + }; + + // Each face gets as id + // The overlay face gets also the id from A and B + struct ID { + ID() + : id(-1), idA(-1), idB(-1), id2(std::size_t(-1), std::size_t(-1)), idA2(std::size_t(-1), std::size_t(-1)), idB2(std::size_t(-1), std::size_t(-1)) + {} + + ID(const ID& other) + :id(other.id), idA(other.idA), idB(other.idB), id2(other.id2), idA2(other.idA2), idB2(other.idB2) + {} + + ID& operator=(const ID& other) + { + id = other.id; + idA = other.idA; + idB = other.idB; + id2 = other.id2; + idA2 = other.idA2; + idB2 = other.idB2; + volA = other.volA; + volB = other.volB; + return *this; + } + + int volA, volB; + int id, idA, idB; + Index id2, idA2, idB2; + }; + + typedef CGAL::Triangulation_vertex_base_with_info_2 Vbi; + typedef CGAL::Triangulation_face_base_with_info_2 Fbi; + typedef CGAL::Constrained_triangulation_face_base_2 Fb; + typedef CGAL::Triangulation_data_structure_2 TDS; + typedef CGAL::Exact_intersections_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + typedef CGAL::Constrained_triangulation_plus_2 CDTplus; + typedef typename CDTplus::Vertex_handle Vertex_handle; + typedef typename CDTplus::Face_handle Face_handle; + typedef typename CDTplus::Finite_vertices_iterator Finite_vertices_iterator; + typedef typename CDTplus::Finite_faces_iterator Finite_faces_iterator; + +private: + struct Sub_partition { + Sub_partition() : parent(static_cast(- 1)) {} + std::shared_ptr m_data; + std::array bbox; + std::vector m_bbox_planes; + std::vector input_polygons; + std::vector > clipped_polygons; + std::vector m_input_planes; + std::size_t parent; + std::vector children; + std::size_t split_plane; + std::size_t index; + + std::vector > face_neighbors; + std::vector > face2vertices; + + std::vector volumes; + //std::vector > face2vertices; + //std::vector exact_vertices; + + typename Octree::Node_index node; + }; + + Parameters m_parameters; + std::array m_bbox; + CGAL::Aff_transformation_3 m_transform; + std::vector m_partition_nodes; // Tree of partitions. + std::vector m_partitions; // Contains the indices of the leaf nodes, the actual partitions to be calculated. + std::vector m_points; + std::vector > m_polygons; + std::vector > m_input_polygons; + std::vector m_input_planes; + std::vector m_input_centroids; + std::vector m_input2regularized; // Mapping from actual input planes to regularized input planes. + std::vector > m_regularized2input; // Mapping from partitioning planes to original input polygons. + std::unique_ptr m_octree; + std::vector m_node2partition; + + std::vector m_volumes; + std::map m_index2volume; + + std::set duplicates; + +public: + /// \name Initialization + /// @{ + /*! + \brief constructs an empty kinetic space partition object. Use `insert()` afterwards to insert polygons into the partition and `initialize()` to initialize the partition. + + \tparam NamedParameters + a sequence of \ref bgl_namedparameters "Named Parameters" + + \param np + a sequence of \ref bgl_namedparameters "Named Parameters" + among the ones listed below + + \cgalNamedParamsBegin + \cgalParamNBegin{verbose} + \cgalParamDescription{Write timing and internal information to `std::cout`.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalParamNBegin{debug} + \cgalParamDescription{Export of intermediate results.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalNamedParamsEnd + */ + template + Kinetic_space_partition_3( + const NamedParameters& np = CGAL::parameters::default_values()) : + m_parameters( + parameters::choose_parameter(parameters::get_parameter(np, internal_np::verbose), false), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::debug), false)), // use true here to export all steps + m_input2regularized() {} + + /*! + \brief constructs a kinetic space partition object and initializes it. + + \tparam PointRange + must be a model of `ConstRange` whose iterator type is `RandomAccessIterator` and whose value type is Point_3. + + \tparam PolygonRange + contains index ranges to form polygons by providing indices into PointRange + + \tparam NamedParameters + a sequence of \ref bgl_namedparameters "Named Parameters" + + \param points + an instance of `PointRange` with 3D points and corresponding 3D normal vectors + + \param polygons + a range of non-coplanar polygons defined by a range of indices into `points` + + \param np + a sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + + \cgalNamedParamsBegin + \cgalParamNBegin{point_map} + \cgalParamDescription{a property map associating points to the elements of the input range PointRange `points`.} + \cgalParamType{a model of `ReadablePropertyMap` whose key type is the value type of the iterator of `PointRange` and whose value type is `GeomTraits::Point_3`} + \cgalParamDefault{`CGAL::Identity_property_map`} + \cgalParamNEnd + \cgalParamNBegin{debug} + \cgalParamDescription{Export of intermediate results.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalParamNBegin{verbose} + \cgalParamDescription{Write timing and internal information to std::cout.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalParamNBegin{reorient_bbox} + \cgalParamDescription{Use the oriented bounding box instead of the axis-aligned bounding box. While the z direction is maintained, the x axis is aligned with the largest variation in the horizontal plane.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalParamNBegin{bbox_dilation_ratio} + \cgalParamDescription{Factor for extension of the bounding box of the input data to be used for the partition.} + \cgalParamType{FT} + \cgalParamDefault{1.1} + \cgalParamNEnd + \cgalParamNBegin{max_octree_depth} + \cgalParamDescription{The maximal depth of the octree for subdividing the kinetic partition before initialization.} + \cgalParamType{std::size_t} + \cgalParamDefault{3} + \cgalParamNEnd + \cgalParamNBegin{max_octree_node_size} + \cgalParamDescription{A node in the octree is only split if the contained number of primitives is larger and the maximal depth is not yet reached.} + \cgalParamType{std::size_t} + \cgalParamDefault{40} + \cgalParamNEnd + \cgalNamedParamsEnd + + + \pre ! points.empty() and ! polygons.empty() + + */ + template< + typename PointRange, + typename PolygonRange, + typename NamedParameters = parameters::Default_named_parameters> + Kinetic_space_partition_3( + const PointRange& points, + const PolygonRange& polygons, + const NamedParameters& np = CGAL::parameters::default_values()) : + m_parameters( + parameters::choose_parameter(parameters::get_parameter(np, internal_np::verbose), false), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::debug), false)), // use true here to export all steps + m_input2regularized() { + insert(points, polygons, np); + initialize(np); + } + + /*! + \brief inserts non-coplanar polygons, requires `initialize()` afterwards to have effect. + + \tparam PointRange + must be a model of `ConstRange` whose iterator type is `RandomAccessIterator` and whose value type is `GeomTraits::Point_3`. + + \tparam PolygonRange + contains index ranges to form polygons by providing indices into PointRange + + \tparam NamedParameters + a sequence of \ref bgl_namedparameters "Named Parameters" + + \param points + an instance of `PointRange` with 3D points + + \param polygons + a range of non-coplanar polygons defined by a range of indices into `points` + + \param np + a sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + + \cgalNamedParamsBegin + \cgalParamNBegin{point_map} + \cgalParamDescription{a property map associating points to the elements of the `points`} + \cgalParamType{a model of `ReadablePropertyMap` whose key type is the value type of the iterator of `PointRange` and whose value type is `GeomTraits::Point_3`} + \cgalParamDefault{`CGAL::Identity_property_map`} + \cgalParamNEnd + \cgalNamedParamsEnd + */ + template + void insert( + const PointRange& points, + const PolygonRange& polygons, + const NamedParameters& np = CGAL::parameters::default_values()) { + + using NP_helper = Point_set_processing_3_np_helper; + using PointMap = typename NP_helper::Point_map; + + PointMap point_map = NP_helper::get_point_map(np); + + To_exact to_exact; + std::size_t offset = m_input2regularized.size(); + + for (std::size_t p = 0; p < polygons.size();p++) { + auto& poly = polygons[p]; + + std::vector pts; + pts.reserve(poly.size()); + for (auto it : poly) + pts.push_back(get(point_map, *(points.begin() + it))); + Plane_3 pl; + Point_2 c; + std::vector ch; + process_input_polygon(pts, pl, c, ch); + typename Intersection_kernel::Plane_3 exact_pl = to_exact(pl); + + // Check if there is already a coplanar polygon inserted + bool skip = false; + for (std::size_t i = 0; i < m_input_planes.size(); i++) { + if (m_input_planes[i] == exact_pl) { + std::cout << i << ". input polygon is coplanar to " << (p + offset) << ". input polygon" << std::endl; + skip = true; + break; + } + } + + if (skip) + continue; + + m_input2regularized.push_back(m_input_planes.size()); + m_regularized2input.push_back(std::vector()); + m_regularized2input.back().push_back(p); + m_input_planes.push_back(to_exact(pl)); + m_input_centroids.push_back(c); + m_input_polygons.push_back(std::vector(ch.size())); + + for (std::size_t i = 0; i < ch.size(); i++) + m_input_polygons.back()[i] = pl.to_3d(ch[i]); + } + } + + /*! + \brief initializes the kinetic partition of the bounding box. + + \tparam NamedParameters + a sequence of \ref bgl_namedparameters "Named Parameters" + + \param np + a sequence of \ref bgl_namedparameters "Named Parameters" + among the ones listed below + + \cgalNamedParamsBegin + \cgalParamNBegin{reorient_bbox} + \cgalParamDescription{Use the oriented bounding box instead of the axis-aligned bounding box. While the z direction is maintained, the x axis is aligned with the largest variation in the horizontal plane.} + \cgalParamType{bool} + \cgalParamDefault{false} + \cgalParamNEnd + \cgalParamNBegin{bbox_dilation_ratio} + \cgalParamDescription{Factor for extension of the bounding box of the input data to be used for the partition.} + \cgalParamType{FT} + \cgalParamDefault{1.1} + \cgalParamNEnd + \cgalParamNBegin{max_octree_depth} + \cgalParamDescription{The maximal depth of the octree for subdividing the kinetic partition before initialization.} + \cgalParamType{std::size_t} + \cgalParamDefault{3} + \cgalParamNEnd + \cgalParamNBegin{max_octree_node_size} + \cgalParamDescription{A node in the octree is only split if the contained number of primitives is larger and the maximal depth is not yet reached.} + \cgalParamType{std::size_t} + \cgalParamDefault{40} + \cgalParamNEnd + \cgalNamedParamsEnd + + \pre input data has been provided via `insert()`. + */ + + template< + typename NamedParameters = parameters::Default_named_parameters> + void initialize( + const NamedParameters& np = CGAL::parameters::default_values()) { + Timer timer; + m_parameters.bbox_dilation_ratio = parameters::choose_parameter( + parameters::get_parameter(np, internal_np::bbox_dilation_ratio), FT(11) / FT(10)); + m_parameters.reorient_bbox = parameters::choose_parameter( + parameters::get_parameter(np, internal_np::reorient_bbox), false); + m_parameters.max_octree_depth = parameters::choose_parameter( + parameters::get_parameter(np, internal_np::max_octree_depth), 3); + m_parameters.max_octree_node_size = parameters::choose_parameter( + parameters::get_parameter(np, internal_np::max_octree_node_size), 40); + + std::cout.precision(20); + if (m_input_polygons.size() == 0) { + std::cout << "Warning: Your input is empty!"; + return; + } + + std::set n; + for (auto p : m_input2regularized) + n.insert(p); + + assert(m_regularized2input.size() == m_input_polygons.size()); + assert(m_regularized2input.size() == n.size()); + + if (m_parameters.bbox_dilation_ratio < FT(1)) { + CGAL_warning_msg(m_parameters.bbox_dilation_ratio >= FT(1), + "Warning: You set enlarge_bbox_ratio < 1.0! The valid range is [1.0, +inf). Setting to 1.0!"); + m_parameters.bbox_dilation_ratio = FT(1); + } + + if (m_parameters.verbose) { + //const std::string is_reorient = (m_parameters.reorient ? "true" : "false"); + + std::cout << std::endl << "--- PARTITION OPTIONS: " << std::endl; + std::cout << "* enlarge bbox ratio: " << m_parameters.bbox_dilation_ratio << std::endl; + } + + if (m_parameters.verbose) { + std::cout << std::endl << "--- INITIALIZING PARTITION:" << std::endl; + + // Initialization. + timer.reset(); + timer.start(); + } + + if (m_parameters.debug) { + for (std::size_t i = 0; i < m_input_polygons.size(); i++) + KSP_3::internal::dump_polygon(m_input_polygons[i], std::to_string(i) + "-input_polygon"); + } + + split_octree(); + m_partitions.resize(m_partition_nodes.size()); + std::iota(m_partitions.begin(), m_partitions.end(), 0); + + for (std::size_t idx : m_partitions) { + Sub_partition& partition = m_partition_nodes[idx]; + partition.index = idx; + + partition.m_data = std::make_shared(m_parameters, std::to_string(idx) + "-"); + + Initializer initializer(partition.clipped_polygons, partition.m_input_planes, *partition.m_data, m_parameters); + initializer.initialize(partition.bbox, partition.input_polygons); + } + + // Timing. + if (m_parameters.verbose) { + const double time_to_initialize = timer.time(); + std::cout << "* initialization time: " << time_to_initialize << std::endl; + } + } + + /*! + \brief propagates the kinetic polygons in the initialized partition. + + \param k + maximum number of allowed intersections for each input polygon before its expansion stops. + + \pre initialized partition and `k != 0` + */ + void partition(std::size_t k) { + FT a, b, c; + partition(k, a, b, c); + } + +#ifndef DOXYGEN_RUNNING + void partition(std::size_t k, FT& partition_time, FT& finalization_time, FT& conformal_time) { + m_volumes.clear(); + Timer timer; + timer.start(); + partition_time = 0; + finalization_time = 0; + conformal_time = 0; + + /* + if (m_parameters.debug) + if (boost::filesystem::is_directory("volumes/")) + for (boost::filesystem::directory_iterator end_dir_it, it("volumes/"); it != end_dir_it; ++it) + boost::filesystem::remove_all(it->path());*/ + + for (std::size_t idx : m_partitions) { + Sub_partition& partition = m_partition_nodes[idx]; + timer.reset(); + std::cout.precision(20); + + // Already initialized? + if (partition.m_data->number_of_support_planes() < 6) { + std::cout << "Kinetic partition not initialized or empty. Number of support planes: " << partition.m_data->number_of_support_planes() << std::endl; + + return; + } + + if (k == 0) { // for k = 0, we skip propagation + std::cout << "k needs to be a positive number" << std::endl; + + return; + } + + if (m_parameters.verbose) { + std::cout << std::endl << "--- RUNNING THE QUEUE:" << std::endl; + std::cout << "* propagation started" << std::endl; + } + + // Propagation. + Propagation propagation(*partition.m_data, m_parameters); + std::size_t m_num_events = propagation.propagate(k); + + partition_time += timer.time(); + + if (m_parameters.verbose) { + std::cout << "* propagation finished" << std::endl; + std::cout << "* number of events handled: " << m_num_events << std::endl; + } + + if (m_parameters.verbose) { + std::cout << std::endl << "--- FINALIZING PARTITION:" << std::endl; + } + + // Finalization. + + for (std::size_t i = 0; i < partition.m_data->number_of_support_planes(); i++) + if (!partition.m_data->support_plane(i).mesh().is_valid(true)) + std::cout << i << ". support has an invalid mesh!" << std::endl; + + for (std::size_t i = 6; i < partition.m_data->number_of_support_planes(); i++) { + bool initial = false; + typename Data_structure::Support_plane& sp = partition.m_data->support_plane(i); + + for (const auto& f : sp.mesh().faces()) + if (sp.is_initial(f)) { + initial = true; + break; + } + + if (!initial) + std::cout << i << " sp has no initial face before" << std::endl; + } + + Finalizer finalizer(*partition.m_data, m_parameters); + + if (m_parameters.verbose) + std::cout << "* getting volumes ..." << std::endl; + + finalizer.create_polyhedra(); + finalization_time += timer.time(); + + for (std::size_t i = 6; i < partition.m_data->number_of_support_planes(); i++) { + bool initial = false; + typename Data_structure::Support_plane& sp = partition.m_data->support_plane(i); + + for (const auto& f : sp.mesh().faces()) + if (sp.is_initial(f)) { + initial = true; + break; + } + + if (!initial) + std::cout << i << " sp has no initial face" << std::endl; + } + + if (m_parameters.verbose) + std::cout << idx << ". partition with " << partition.input_polygons.size() << " input polygons split into " << partition.m_data->number_of_volumes() << " volumes" << std::endl; + } + + // Convert face_neighbors to pair + for (std::size_t i = 0; i < m_partitions.size(); i++) { + Sub_partition& partition = m_partition_nodes[m_partitions[i]]; + + for (std::size_t j = 0; j < partition.m_data->number_of_volumes(); j++) { + m_volumes.push_back(std::make_pair(m_partitions[i], j)); + } + + partition.face_neighbors.resize(partition.m_data->face_to_volumes().size()); + for (std::size_t j = 0; j < partition.m_data->face_to_volumes().size(); j++) { + auto& p = partition.m_data->face_to_volumes()[j]; + partition.face_neighbors[j] = std::make_pair(Index(m_partitions[i], p.first), Index(m_partitions[i], p.second)); + } + + partition.face2vertices.resize(partition.m_data->face_to_vertices().size()); + + for (std::size_t j = 0; j < partition.m_data->face_to_vertices().size(); j++) { + partition.face2vertices[j].resize(partition.m_data->face_to_vertices()[j].size()); + for (std::size_t k = 0; k < partition.m_data->face_to_vertices()[j].size(); k++) + partition.face2vertices[j][k] = std::make_pair(m_partitions[i], partition.m_data->face_to_vertices()[j][k]); + } + } + + for (std::size_t i = 0; i < m_volumes.size(); i++) + m_index2volume[m_volumes[i]] = i; + + std::map pts2idx; + + for (std::size_t i = 0; i < number_of_volumes(); i++) { + std::vector f1; + faces(i, std::back_inserter(f1)); + for (const Index& f : f1) { + std::vector& face = m_partition_nodes[f.first].face2vertices[f.second]; + for (std::size_t j = 0; j < face.size(); j++) { + auto it = pts2idx.emplace(m_partition_nodes[face[j].first].m_data->exact_vertices()[face[j].second], face[j]); + if (!it.second) + face[j] = it.first->second; + } + } + } + + timer.stop(); + + timer.reset(); + timer.start(); + make_conformal(0); + conformal_time = timer.time(); + +// if (m_parameters.verbose) +// check_tjunctions(); + + // Clear unused data structures + for (std::size_t i = 0; i < m_partitions.size(); i++) { + m_partition_nodes[i].m_data->pface_neighbors().clear(); + m_partition_nodes[i].m_data->face_to_vertices().clear(); + m_partition_nodes[i].m_data->face_to_index().clear(); + m_partition_nodes[i].m_data->face_to_volumes().clear(); + } + + std::cout << "ksp v: " << m_partition_nodes[0].m_data->vertices().size() << " f: " << m_partition_nodes[0].face2vertices.size() << " vol: " << m_volumes.size() << std::endl; + + return; + } +#endif + /// @} + + /******************************* + ** Access ** + ********************************/ + + /// \name Access + /// @{ + + /*! + \brief returns the number of volumes created by the kinetic partition. + + \pre created partition + */ + std::size_t number_of_volumes() const { + return m_volumes.size(); + } + + /*! + \brief provides the support planes of the partition derived from the input polygons + + @return + vector of planes. + + \pre inserted polygons + */ + const std::vector &input_planes() const { + return m_input_planes; + } + + /*! + \brief exports the kinetic partition into a `Linear_cell_complex_for_combinatorial_map<3, 3>` using a model of `KineticLCCItems` as items, e.g., `Kinetic_space_partition_3::Linear_cell_complex_min_items`. + + Volume and face attributes defined in the model `KineticLCCItems` are filled. The volume index is in the range [0, number of volumes -1] + + \tparam LCC must be a model of `Linear_cell_complex_for_combinatorial_map<3, 3>` using a model of `KineticLCCItems`. + + \param lcc instance of LCC to be filled with the kinetic partition. Any data contained in `lcc` will be cleared before. + + \pre created partition + */ + template + void get_linear_cell_complex(LCC &lcc) const { + lcc.clear(); + + std::map mapped_vertices; + std::map mapped_points; + std::vector vtx; + std::vector vtx_index; + + using LCC_kernel = typename CGAL::Kernel_traits::Kernel; + + using To_lcc = CGAL::Cartesian_converter; + + To_lcc to_lcc; + + To_exact to_exact; + + std::vector faces_of_volume, vtx_of_face; + std::vector pts_of_face; + + for (std::size_t i = 0; i < number_of_volumes(); i++) { + faces(i, std::back_inserter(faces_of_volume)); + + for (const Index& f : faces_of_volume) { + exact_vertices(f, std::back_inserter(pts_of_face), std::back_inserter(vtx_of_face)); + + for (std::size_t j = 0; j < pts_of_face.size(); j++) { + auto pit = mapped_points.emplace(pts_of_face[j], vtx.size()); + if (pit.second) { + mapped_vertices[vtx_of_face[j]] = vtx.size(); + vtx.push_back(pts_of_face[j]); + vtx_index.push_back(vtx_of_face[j]); + } + else mapped_vertices[vtx_of_face[j]] = pit.first->second; + } + + pts_of_face.clear(); + vtx_of_face.clear(); + } + faces_of_volume.clear(); + } + + CGAL::Linear_cell_complex_incremental_builder_3 ib(lcc); + for (std::size_t i = 0; i < vtx.size(); i++) + ib.add_vertex(to_lcc(vtx[i])); + + std::size_t num_faces = 0; + //std::size_t num_vols = 0; + //std::size_t num_vtx = 0; + + typename LCC::Dart_descriptor d; + + std::vector used_vertices(mapped_vertices.size(), false); + std::vector added_volumes(number_of_volumes(), false); + std::deque queue; + queue.push_back(0); + while (!queue.empty()) { + std::size_t v = queue.front(); + queue.pop_front(); + + if (added_volumes[v]) + continue; + + if (!can_add_volume_to_lcc(v, added_volumes, mapped_vertices, used_vertices)) { + queue.push_back(v); + continue; + } + + added_volumes[v] = true; + + ib.begin_surface(); + //std::cout << v << " inserting:"; + //num_vols++; + faces(v, std::back_inserter(faces_of_volume)); + + typename Intersection_kernel::Point_3 centroid = to_exact(m_partition_nodes[m_volumes[v].first].m_data->volumes()[m_volumes[v].second].centroid); + + /* + std::ofstream vout3(std::to_string(v) + ".xyz"); + vout3.precision(20); + vout3 << " " << m_partition_nodes[m_volumes[v].first].m_data->volumes()[m_volumes[v].second].centroid << std::endl; + vout3 << std::endl; + vout3.close();*/ + + // How to order faces accordingly? + // First take faces of adjacent volumes and collect all added edges + // Then pick from the remaining faces and take those which have already inserted edges + // Repeat the last step until all are done. + // std::set > edges; + // for (std::size_t j=0;) + // Try easy way and remove cells, I did not add after every loop? + + for (std::size_t j = 0; j < faces_of_volume.size(); j++) { + vertex_indices(faces_of_volume[j], std::back_inserter(vtx_of_face)); + + auto pair = neighbors(faces_of_volume[j]); + + if (pair.first != static_cast(v) && !added_volumes[pair.first]) + queue.push_back(pair.first); + if (pair.second != static_cast(v) && pair.second >= 0 && !added_volumes[pair.second]) + queue.push_back(pair.second); + + //auto vertex_range = m_data.pvertices_of_pface(vol.pfaces[i]); + ib.begin_facet(); + num_faces++; + + //std::cout << "("; + + //Sub_partition& p = m_partition_nodes[faces_of_volume[j].first]; + + typename Intersection_kernel::Vector_3 norm; + std::size_t i = 0; + do { + std::size_t n = (i + 1) % vtx_of_face.size(); + std::size_t nn = (n + 1) % vtx_of_face.size(); + norm = CGAL::cross_product(vtx[mapped_vertices[vtx_of_face[n]]] - vtx[mapped_vertices[vtx_of_face[i]]], vtx[mapped_vertices[vtx_of_face[nn]]] - vtx[mapped_vertices[vtx_of_face[n]]]); + i++; + } while (norm.squared_length() == 0 && i < vtx_of_face.size()); + + typename Intersection_kernel::FT len = CGAL::approximate_sqrt(norm.squared_length()); + if (len != 0) + len = 1.0 / len; + norm = norm * len; + + bool outwards_oriented = (vtx[mapped_vertices[vtx_of_face[0]]] - centroid) * norm < 0; + //outward[std::make_pair(v, j)] = outwards_oriented; + + if (!outwards_oriented) + std::reverse(vtx_of_face.begin(), vtx_of_face.end()); + + /* + auto p1 = edge_to_volface.emplace(std::make_pair(std::make_pair(mapped_vertices[vtx_of_face[0]], mapped_vertices[vtx_of_face[1]]), std::make_pair(v, j))); + if (!p1.second) { + std::size_t first = mapped_vertices[vtx_of_face[0]]; + std::size_t second = mapped_vertices[vtx_of_face[1]]; + auto p = edge_to_volface[std::make_pair(first, second)]; + auto o1 = outward[p]; + auto o2 = outward[std::make_pair(v, j)]; + } + + for (std::size_t k = 1; k < vtx_of_face.size() - 1; k++) { + auto p = edge_to_volface.emplace(std::make_pair(std::make_pair(mapped_vertices[vtx_of_face[k]], mapped_vertices[vtx_of_face[k + 1]]), std::make_pair(v, j))); + if (!p.second) { + std::size_t first = mapped_vertices[vtx_of_face[k]]; + std::size_t second = mapped_vertices[vtx_of_face[k + 1]]; + auto p = edge_to_volface[std::make_pair(first, second)]; + auto o1 = outward[p]; + auto o2 = outward[std::make_pair(v, j)]; + } + } + + auto p2 = edge_to_volface.emplace(std::make_pair(std::make_pair(mapped_vertices[vtx_of_face.back()], mapped_vertices[vtx_of_face[0]]), std::make_pair(v, j))); + if (!p2.second) { + std::size_t first = mapped_vertices[vtx_of_face.back()]; + std::size_t second = mapped_vertices[vtx_of_face[0]]; + auto p = edge_to_volface[std::make_pair(first, second)]; + auto o1 = outward[p]; + auto o2 = outward[std::make_pair(v, j)]; + }*/ + + for (const Index& v : vtx_of_face) { + ib.add_vertex_to_facet(static_cast(mapped_vertices[v])); + //std::cout << " " << mapped_vertices[v]; + if (!used_vertices[mapped_vertices[v]]) { + used_vertices[mapped_vertices[v]] = true; + //num_vtx++; + } + } + + //std::cout << ")"; + auto face_dart = ib.end_facet(); // returns a dart to the face + if (lcc.template attribute<2>(face_dart) == lcc.null_descriptor) { + lcc.template set_attribute<2>(face_dart, lcc.template create_attribute<2>()); + // How to handle bbox planes that coincide with input polygons? Check support plane + std::size_t sp = m_partition_nodes[faces_of_volume[j].first].m_data->face_to_support_plane()[faces_of_volume[j].second]; + + // There are three different cases: + // 1. face belongs to a plane from an input polygon + // 2. face originates from octree splitting (and does not have an input plane) + // 3. face lies on the bbox + int ip = static_cast(m_partition_nodes[faces_of_volume[j].first].m_data->support_plane(sp).data().actual_input_polygon); + if (ip != -1) + lcc.template info<2>(face_dart).input_polygon_index = static_cast(m_partition_nodes[faces_of_volume[j].first].input_polygons[ip]); + else { + // If there is no input polygon, I need to check whether it has two neighbors + auto n = neighbors(faces_of_volume[j]); + if (n.second >= 0) + lcc.template info<2>(face_dart).input_polygon_index = static_cast(-7); + else + lcc.template info<2>(face_dart).input_polygon_index = static_cast(n.second); + } + lcc.template info<2>(face_dart).part_of_initial_polygon = m_partition_nodes[faces_of_volume[j].first].m_data->face_is_part_of_input_polygon()[faces_of_volume[j].second]; + lcc.template info<2>(face_dart).plane = m_partition_nodes[faces_of_volume[j].first].m_data->support_plane(m_partition_nodes[faces_of_volume[j].first].m_data->face_to_support_plane()[faces_of_volume[j].second]).exact_plane(); + } + else { + assert(lcc.template info<2>(face_dart).part_of_initial_polygon == m_partition_nodes[faces_of_volume[j].first].m_data->face_is_part_of_input_polygon()[faces_of_volume[j].second]); + } + + vtx_of_face.clear(); + } + + d = ib.end_surface(); + + auto ah = lcc.template create_attribute<3>(); + lcc.template set_attribute<3>(d, ah); + lcc.template info<3>(d).barycenter = centroid; + lcc.template info<3>(d).volume_id = v; + + faces_of_volume.clear(); + } + + // Todo: Remove check if all volumes were added + for (std::size_t i = 0; i < added_volumes.size(); i++) + if (!added_volumes[i]) + std::cout << "volume " << i << " has not been added" << std::endl; + + if (m_parameters.verbose) { + std::cout << "lcc #volumes: " << lcc.template one_dart_per_cell<3>().size() << " ksp #volumes: " << number_of_volumes() << std::endl; + std::cout << "lcc #faces: " << lcc.template one_dart_per_cell<2>().size() << " ksp #faces: " << num_faces << std::endl; + std::cout << "lcc #n-edges: " << lcc.template one_dart_per_cell<1>().size() << std::endl; + std::cout << "lcc #vtx: " << lcc.template one_dart_per_cell<0>().size() << " ksp #vtx: " << vtx.size() << std::endl; + } + + // Verification + // Check attributes in each dart + for (auto& d : lcc.template one_dart_per_cell<0>()) { + if (!lcc.is_dart_used(lcc.dart_descriptor(d))) { + std::cout << "unused dart in 0" << std::endl; + } + } + for (auto& d : lcc.template one_dart_per_cell<1>()) { + if (!lcc.is_dart_used(lcc.dart_descriptor(d))) { + std::cout << "unused dart in 1" << std::endl; + } + } + for (auto& d : lcc.template one_dart_per_cell<2>()) { + if (!lcc.is_dart_used(lcc.dart_descriptor(d))) { + std::cout << "unused dart in 2" << std::endl; + } + } + for (auto& d : lcc.template one_dart_per_cell<3>()) { + if (!lcc.is_dart_used(lcc.dart_descriptor(d))) { + std::cout << "unused dart in 3" << std::endl; + } + } + + if (m_parameters.verbose) + lcc.display_characteristics(std::cout) << std::endl; + + if (!lcc.is_valid()) + std::cout << "LCC is not valid" << std::endl; + } + + /// @} + +private: + struct Constraint_info { + typename CDTplus::Constraint_id id_single, id_merged, id_overlay; + std::size_t volume; + Index vA, vB; + }; + + const Point_3& volume_centroid(std::size_t volume_index) const { + assert(volume_index < m_volumes.size()); + auto p = m_volumes[volume_index]; + return m_partition_nodes[p.first].m_data->volumes()[p.second].centroid; + } + + + template + void faces_of_input_polygon(const std::size_t polygon_index, OutputIterator it) const { + if (polygon_index >= m_input_planes.size()) { + assert(false); + } + + for (std::size_t idx : m_partitions) { + const Sub_partition& p = m_partition_nodes[idx]; + // Check if it contains this input polygon and get support plane index + int sp_idx = -1; + for (std::size_t i = 0; i < p.input_polygons.size(); i++) { + if (p.input_polygons[i] == polygon_index) { + sp_idx = p.m_data->support_plane_index(i); + break; + } + } + + // Continue if the partition does not contain this input polygon. + if (sp_idx == -1) + continue; + + auto pfaces = p.m_data->pfaces(sp_idx); + auto f2i = p.m_data->face_to_index(); + const auto& f2sp = p.m_data->face_to_support_plane(); + + for (std::size_t i = 0; i < f2sp.size(); i++) { + if (f2sp[i] == sp_idx) + *it++ = std::make_pair(idx, i); + } + } + } + + const std::vector >& input_mapping() const { + return m_regularized2input; + } + + /*! + \brief Face indices of the volume. + + \param volume_index + index of the query volume. + + @return + vector of face indices. + + \pre created partition + */ + template + void faces(std::size_t volume_index, OutputIterator it) const { + CGAL_assertion(m_volumes.size() > volume_index); + auto p = m_volumes[volume_index]; + + for (std::size_t i : m_partition_nodes[p.first].m_data->volumes()[p.second].faces) + *it++ = std::make_pair(p.first, i); + } + + + /*! + \brief Mapping of a vertex index to its position. + + @return + vector of points. + + \pre created partition + */ + const Point_3& vertex(const Index& vertex_index) const { + return m_partition_nodes[vertex_index.first].m_data->vertices()[vertex_index.second]; + } + + /*! + \brief Mapping of a vertex index to its exact position. + + @return + vector of points. + + \pre created partition + */ + const typename Intersection_kernel::Point_3& exact_vertex(const Index& vertex_index) const { + return m_partition_nodes[vertex_index.first].m_data->exact_vertices()[vertex_index.second]; + } + + /*! + \brief Vertices of a face. + + \param volume_index + index of the query volume. + + @return + vector of face indices. + + \pre created partition + */ + template + void vertices(const Index& face_index, OutputIterator it) const { + for (auto& p : m_partition_nodes[face_index.first].face2vertices[face_index.second]) + *it++ = m_partition_nodes[p.first].m_data->vertices()[p.second]; + } + + template + void vertex_indices(const Index& face_index, OutputIterator it) const { + for (auto& p : m_partition_nodes[face_index.first].face2vertices[face_index.second]) + *it++ = p; + } + + /*! + \brief Vertices of a face. + + \param volume_index + index of the query volume. + + @return + vector of face indices. + + \pre created partition + */ + template + void exact_vertices(const Index& face_index, OutputIterator it) const { + + for (auto& p : m_partition_nodes[face_index.first].face2vertices[face_index.second]) + *it++ = m_partition_nodes[p.first].m_data->exact_vertices()[p.second]; + } + + template + void exact_vertices(const Index& face_index, OutputIterator pit, IndexOutputIterator iit) const { + for (auto& p : m_partition_nodes[face_index.first].face2vertices[face_index.second]) { + *iit++ = p; + *pit++ = m_partition_nodes[p.first].m_data->exact_vertices()[p.second]; + } + } + + + /*! + \brief Indices of adjacent volumes. Negative indices correspond to the empty spaces behind the sides of the bounding box. + + \param face_index + index of the query face. + + @return + pair of adjacent volumes. + + -1 zmin + -2 ymin + -3 xmax + -4 ymax + -5 xmin + -6 zmax + + \pre created partition + */ + std::pair neighbors(const Index &face_index) const { + const auto &p = m_partition_nodes[face_index.first].face_neighbors[face_index.second]; + if (p.second.second >= std::size_t(-6)) { // Faces on the boundary box are neighbors with an infinite outside volume + auto it = m_index2volume.find(p.first); + assert(it != m_index2volume.end()); + return std::pair(static_cast(it->second), static_cast(p.second.second)); + } + else { + auto it1 = m_index2volume.find(p.first); + assert(it1 != m_index2volume.end()); + auto it2 = m_index2volume.find(p.second); + assert(it2 != m_index2volume.end()); + return std::pair(static_cast(it1->second), static_cast(it2->second)); + } + } + + void process_input_polygon(const std::vector poly, Plane_3& pl, Point_2& c, std::vector& ch) const { + CGAL::linear_least_squares_fitting_3(poly.begin(), poly.end(), pl, CGAL::Dimension_tag<0>()); + + std::vector pts2d(poly.size()); + for (std::size_t i = 0; i < poly.size(); i++) + pts2d[i] = pl.to_2d(poly[i]); + + ch.clear(); + CGAL::convex_hull_2(pts2d.begin(), pts2d.end(), std::back_inserter(ch)); + + // Centroid + FT x = 0, y = 0, w = 0; + for (std::size_t i = 2; i < ch.size(); i++) { + Triangle_2 tri(ch[0], ch[i - 1], ch[i]); + w += CGAL::area(ch[0], ch[i - 1], ch[i]); + Point_2 c = CGAL::centroid(ch[0], ch[i - 1], ch[i]); + x += c.x() * w; + y += c.y() * w; + } + + c = Point_2(x / w, y / w); + } + + std::pair make_canonical_pair(int i, int j) { + if (i > j) return std::make_pair(j, i); + return std::make_pair(i, j); + } + + double build_cdt(CDTplus& cdt, std::vector& faces, std::vector >& constraints, const typename Intersection_kernel::Plane_3& plane) { + double area = 0; + From_exact from_exact; + + cdt.clear(); + //keep track of constraints when inserting to iterate later + constraints.resize(faces.size()); + + //check orientation of faces so that they are ccw oriented + std::vector > pts_idx(faces.size()); + std::vector > pts(faces.size()); + for (std::size_t i = 0; i < faces.size(); ++i) { + exact_vertices(faces[i], std::back_inserter(pts[i]), std::back_inserter(pts_idx[i])); + constraints[i].resize(pts[i].size()); + + CGAL::Orientation res = CGAL::COLLINEAR; + bool pos = false; + bool neg = false; + + for (std::size_t j = 0; j < pts[i].size(); j++) { + std::size_t k = (j + 1) % pts[i].size(); + std::size_t l = (k + 1) % pts[i].size(); + + res = orientation(plane.to_2d(pts[i][j]), plane.to_2d(pts[i][k]), plane.to_2d(pts[i][l])); + if (res == CGAL::LEFT_TURN) + pos = true; + if (res == CGAL::RIGHT_TURN) + neg = true; + } + + if (pos && neg) { + std::cout << "face is not convex" << std::endl; + exit(1); + } + + if (!pos && !neg) { + std::cout << "face is degenerated" << std::endl; + exit(1); + } + + if (neg) { + std::reverse(pts[i].begin(), pts[i].end()); + std::reverse(pts_idx[i].begin(), pts_idx[i].end()); + } + } + + std::map face2vtx; + std::map vtx2face; + std::vector vertices; + for (std::size_t f = 0; f < faces.size(); f++) + for (std::size_t v = 0; v < pts_idx[f].size(); v++) { + vertices.push_back(cdt.insert(plane.to_2d(pts[f][v]))); + + if (vertices.back()->info().idA2.first != static_cast(-1) && vertices.back()->info().idA2 != pts_idx[f][v]) { + std::cout << "build_cdt faces has non-unique vertices" << std::endl; + } + + vertices.back()->info().idA2 = pts_idx[f][v]; + assert(pts_idx[f][v].first != static_cast(-1)); + assert(pts_idx[f][v].second != static_cast(-1)); + vertices.back()->info().adjacent.insert(faces[f]); + vertices.back()->info().set_point(pts[f][v]); + face2vtx[pts_idx[f][v]] = vertices.size() - 1; + vtx2face[vertices.size() - 1] = pts_idx[f][v]; + } + + typedef std::set > Edges; + Edges edges; + + // Iterating over each face and inserting each edge as a constraint. + for (std::size_t i = 0; i < pts_idx.size(); ++i) { + auto& v = pts_idx[i]; + for (std::size_t j = 0; j < v.size(); ++j) { + int vj = static_cast(face2vtx[v[j]]); + int vjj = static_cast(face2vtx[v[(j + 1) % v.size()]]); + std::pair res = edges.insert(make_canonical_pair(vj, vjj)); + + if (res.second) { + constraints[i][j].id_single = cdt.insert_constraint(vertices[vj], vertices[vjj]); + auto p = neighbors(faces[i]); + if (p.second >= 0) + std::cout << "p.second is positive" << std::endl; + if (p.first < 0) + std::cout << "p.first is negative" << std::endl; + constraints[i][j].volume = p.first; + constraints[i][j].vA = v[j]; + constraints[i][j].vB = v[(j + 1) % v.size()]; + } + } + } + + for (typename CDTplus::Finite_faces_iterator fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) { + std::set& a(fit->vertex(0)->info().adjacent), & b(fit->vertex(1)->info().adjacent), & c(fit->vertex(2)->info().adjacent); + + std::set res, res2; + std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(res, res.begin())); + std::set_intersection(res.begin(), res.end(), c.begin(), c.end(), std::inserter(res2, res2.begin())); + + if (res2.size() != 1) { + std::cout << "build_cdt: face assignment not unique!" << std::endl; + const std::string vfilename = "no-face.polylines.txt"; + std::ofstream vout(vfilename); + vout.precision(20); + vout << 4; + vout << " " << from_exact(plane.to_3d(fit->vertex(0)->point())); + vout << " " << from_exact(plane.to_3d(fit->vertex(1)->point())); + vout << " " << from_exact(plane.to_3d(fit->vertex(2)->point())); + vout << " " << from_exact(plane.to_3d(fit->vertex(0)->point())); + vout << std::endl; + vout.close(); + } + else fit->info().id2 = *res2.begin(); + } + + return area; + } + + void check_tjunctions() { + std::map > vertex2neighbors; + + for (std::size_t v = 0; v < m_volumes.size(); v++) { + auto &vp = m_volumes[v]; + for (const std::size_t f : m_partition_nodes[vp.first].m_data->volumes()[vp.second].faces) { + auto& vtx = m_partition_nodes[vp.first].face2vertices[f]; + for (std::size_t i = 0; i < vtx.size(); i++) { + vertex2neighbors[vtx[i]].push_back(vtx[(i + 1) % vtx.size()]); + vertex2neighbors[vtx[i]].push_back(vtx[(i - 1 + vtx.size()) % vtx.size()]); + } + } + } + + for (auto& p : vertex2neighbors) { + typename Intersection_kernel::Point_3 a = m_partition_nodes[p.first.first].m_data->exact_vertices()[p.first.second]; + //Check pairwise collinear + for (std::size_t i = 0; i < p.second.size(); i++) { + typename Intersection_kernel::Point_3 b = m_partition_nodes[p.second[i].first].m_data->exact_vertices()[p.second[i].second]; + for (std::size_t j = i + 1; j < p.second.size(); j++) { + if (p.second[i] == p.second[j]) + continue; + typename Intersection_kernel::Point_3 c = m_partition_nodes[p.second[j].first].m_data->exact_vertices()[p.second[j].second]; + if (CGAL::collinear(a, b, c) && ((b - a) * (c - a) > 0)) { + std::cout << "non-manifold v (" << p.first.first << ", " << p.first.second << ")" << std::endl; + std::cout << " v (" << p.second[i].first << ", " << p.second[i].second << ")" << std::endl; + std::cout << " v (" << p.second[j].first << ", " << p.second[j].second << ")" << std::endl; + + From_exact from_exact; + + std::ofstream vout2("a.xyz"); + vout2.precision(20); + vout2 << from_exact(a) << std::endl; + vout2.close(); + std::ofstream vout3("b.xyz"); + vout3.precision(20); + vout3 << from_exact(b) << std::endl; + vout3.close(); + std::ofstream vout4("c.xyz"); + vout4.precision(20); + vout4 << from_exact(c) << std::endl; + vout4.close(); + + for (std::size_t v = 0; v < m_volumes.size(); v++) { + auto& vp = m_volumes[v]; + for (const std::size_t f : m_partition_nodes[vp.first].m_data->volumes()[vp.second].faces) { + auto& vtx = m_partition_nodes[vp.first].face2vertices[f]; + bool hasa = false, hasb = false, hasc = false; + for (std::size_t k = 0; k < vtx.size(); k++) { + if (vtx[k] == p.first) + hasa = true; + if (vtx[k] == p.second[i]) + hasb = true; + if (vtx[k] == p.second[j]) + hasc = true; + } + + if (hasa && (hasb || hasc)) { + const std::string vfilename = std::to_string(v) + " " + std::to_string(f) + "-non_manifold.polylines.txt"; + std::ofstream vout(vfilename); + vout.precision(20); + vout << vtx.size() + 1; + for (const auto& v : vtx) { + vout << " " << from_exact(m_partition_nodes[v.first].m_data->exact_vertices()[v.second]); + } + + vout << " " << from_exact(m_partition_nodes[vtx[0].first].m_data->exact_vertices()[vtx[0].second]); + + vout << std::endl; + vout.close(); + } + } + } + std::cout << std::endl; + } + } + } + } + } + + void insert_map(const Index& a, const Index& b, std::map& pm) const { + if (a == b) + return; + + Index target = b; + auto it = pm.find(b); + if (it != pm.end()) + target = it->second; + pm[a] = target; + } + + void build_cdt(CDTplus& cdt, std::vector& partitions, std::vector > >& constraints, const typename Intersection_kernel::Plane_3& plane) { + if (partitions.size() == 0) + return; + + for (std::size_t i = 0; i < partitions.size(); i++) { + std::vector vertices; + vertices.reserve(6); + + for (std::size_t j = 0; j < constraints[i].size(); j++) + for (std::size_t k = 0; k < constraints[i][j].size(); k++) { + if (constraints[i][j][k].id_single == 0) + continue; + for (typename CDTplus::Vertices_in_constraint_iterator vi = partitions[i].vertices_in_constraint_begin(constraints[i][j][k].id_single); vi != partitions[i].vertices_in_constraint_end(constraints[i][j][k].id_single); vi++) { + vertices.push_back(*vi); + } + + // Insert constraints and replacing vertex handles in vector while copying data. + VI tmp = vertices[0]->info(); + vertices[0] = cdt.insert(vertices[0]->point()); + vertices[0]->info() = tmp; + + tmp = vertices.back()->info(); + vertices.back() = cdt.insert(vertices.back()->point()); + vertices.back()->info() = tmp; + + constraints[i][j][k].id_merged = cdt.insert_constraint(vertices[0], vertices.back()); + + vertices.clear(); + } + } + + // Generate 3D points corresponding to the intersections + //std::size_t newpts = 0; + for (typename CDTplus::Finite_vertices_iterator vit = cdt.finite_vertices_begin(); vit != cdt.finite_vertices_end(); ++vit) { + if (!vit->info().input) { + vit->info().point_3 = plane.to_3d(vit->point()); + vit->info().idA2 = vit->info().idB2 = Index(-1, -1); + //newpts++; + } + } + + for (typename CDTplus::Finite_faces_iterator fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) { + Index idx(std::size_t(-1), std::size_t(-1)); + + typename Intersection_kernel::Point_2 pt = CGAL::centroid(fit->vertex(0)->point(), fit->vertex(1)->point(), fit->vertex(2)->point()); + for (std::size_t i = 0; i < partitions.size(); i++) { + typename CDTplus::Face_handle fh = partitions[i].locate(pt); + + if (!partitions[i].is_infinite(fh)) { + if (fh->info().id2 != std::make_pair(std::size_t(-1), std::size_t(-1))) + idx = fit->info().id2 = fh->info().id2; + else + std::cout << "Face id is missing " << std::endl; + } + } + + if (fit->info().id2.first == std::size_t(-1)) + std::cout << "cdt fusion: no id found" << std::endl; + } + } + + std::pair overlay(CDTplus& cdtC, const CDTplus& cdtA, std::vector > >& constraints_a, const CDTplus& cdtB, std::vector > >& constraints_b, const typename Intersection_kernel::Plane_3& plane) { + From_exact from_exact; + //To_exact to_exact; + std::pair result; + cdtC = cdtA; + + std::vector vertices; + vertices.reserve(2); + + for (std::size_t i = 0; i < constraints_a.size(); i++) + for (std::size_t j = 0; j < constraints_a[i].size(); j++) + for (std::size_t k = 0; k < constraints_a[i][j].size(); k++) { + if (constraints_a[i][j][k].id_merged == 0) { + if (constraints_a[i][j][k].id_single != 0) + constraints_a[i][j][k].id_merged = constraints_a[i][j][k].id_single; + else + continue; + } + + for (typename CDTplus::Vertices_in_constraint_iterator vi = cdtA.vertices_in_constraint_begin(constraints_a[i][j][k].id_merged); vi != cdtA.vertices_in_constraint_end(constraints_a[i][j][k].id_merged); vi++) { + vertices.push_back(*vi); + } + + // Insert constraints and replacing vertex handles in vector while copying data. + VI tmp = vertices[0]->info(); + vertices[0] = cdtC.insert(vertices[0]->point()); + vertices[0]->info() = tmp; + + tmp = vertices.back()->info(); + vertices.back() = cdtC.insert(vertices.back()->point()); + vertices.back()->info() = tmp; + + constraints_a[i][j][k].id_overlay = cdtC.insert_constraint(vertices[0], vertices.back()); + + vertices.clear(); + } + + for (std::size_t i = 0; i < constraints_b.size(); i++) + for (std::size_t j = 0; j < constraints_b[i].size(); j++) + for (std::size_t k = 0; k < constraints_b[i][j].size(); k++) { + if (constraints_b[i][j][k].id_merged == 0) { + if (constraints_b[i][j][k].id_single != 0) + constraints_b[i][j][k].id_merged = constraints_b[i][j][k].id_single; + else + continue; + } + for (typename CDTplus::Vertices_in_constraint_iterator vi = cdtB.vertices_in_constraint_begin(constraints_b[i][j][k].id_merged); vi != cdtB.vertices_in_constraint_end(constraints_b[i][j][k].id_merged); vi++) { + vertices.push_back(*vi); + } + + // Insert constraints and replacing vertex handles in vector while copying data. + VI tmp = vertices[0]->info(); + vertices[0] = cdtC.insert(vertices[0]->point()); + vertices[0]->info() = tmp; + + tmp = vertices.back()->info(); + vertices.back() = cdtC.insert(vertices.back()->point()); + vertices.back()->info() = tmp; + + constraints_b[i][j][k].id_overlay = cdtC.insert_constraint(vertices[0], vertices.back()); + + vertices.clear(); + } + + //std::size_t newpts = 0; + // Generate 3D points corresponding to the intersections + for (typename CDTplus::Finite_vertices_iterator vit = cdtC.finite_vertices_begin(); vit != cdtC.finite_vertices_end(); ++vit) { + if (!vit->info().input) { + vit->info().point_3 = plane.to_3d(vit->point()); + vit->info().idA2 = vit->info().idB2 = Index(-1, -1); + //newpts++; + } + } + + for (typename CDTplus::Finite_faces_iterator cit = cdtC.finite_faces_begin(); cit != cdtC.finite_faces_end(); ++cit) { + double a = 0; + cit->info().id2 = std::make_pair(-1, -1); + + typename Intersection_kernel::Point_2 p = CGAL::centroid(cit->vertex(0)->point(), cit->vertex(1)->point(), cit->vertex(2)->point()); + typename CDTplus::Face_handle fhA = cdtA.locate(p); + + if (cdtA.is_infinite(fhA)) + std::cout << "No face located in A: " << from_exact(plane.to_3d(p)) << std::endl; + + if (fhA->info().id2 != std::make_pair(std::size_t(-1), std::size_t(-1))) { + cit->info().idA2 = fhA->info().id2; + result.first += a; + } + else + std::cout << "Face in A is missing ID " << from_exact(plane.to_3d(p)) << std::endl; + + typename CDTplus::Face_handle fhB = cdtB.locate(p); + if (cdtB.is_infinite(fhB)) + std::cout << "No face located in B: " << from_exact(plane.to_3d(p)) << std::endl; + + if (fhB->info().id2 != std::make_pair(std::size_t(-1), std::size_t(-1))) { + cit->info().idB2 = fhB->info().id2; + result.second += a; + } + else + std::cout << "Face in B is missing ID " << from_exact(plane.to_3d(p)) << std::endl; + } + + return result; + } + + void collect_faces(std::size_t partition_idx, std::size_t sp_idx, std::vector& faces, typename Intersection_kernel::Plane_3& plane) { + Sub_partition& p = m_partition_nodes[partition_idx]; + + plane = p.m_data->support_plane(sp_idx).data().exact_plane; + + const std::vector& f2sp = p.m_data->face_to_support_plane(); + + for (std::size_t i = 0; i < f2sp.size(); i++) + if (f2sp[i] == sp_idx) + faces.push_back(std::make_pair(partition_idx, i)); + } + + void collect_faces(Octree_node node, std::size_t dimension, bool lower, std::vector& faces, typename Intersection_kernel::Plane_3& plane) { + // Collects boundary faces of node from its children. + // dimension specifies the axis of the boundary face and lower determines if it is the lower of upper face of the cube on the axis. + + // Support plane indices: + // xmin 4, xmax 2 + // ymin 1, ymax 3 + // zmin 0, zmax 5 + + if (m_octree->is_leaf(node)) { + // Mapping to partition is needed. + std::size_t idx = m_node2partition[node]; + + if (lower) + switch (dimension) { + case 0: + collect_faces(idx, 4, faces, plane); + break; + case 1: + collect_faces(idx, 1, faces, plane); + break; + case 2: + collect_faces(idx, 0, faces, plane); + break; + } + else + switch (dimension) { + case 0: + collect_faces(idx, 2, faces, plane); + break; + case 1: + collect_faces(idx, 3, faces, plane); + break; + case 2: + collect_faces(idx, 5, faces, plane); + break; + } + + return; + } + else { + typename Intersection_kernel::Plane_3 pl2, pl3, pl4; + if (lower) + switch (dimension) { + case 0://0246 + collect_faces(m_octree->child(node, 0), dimension, true, faces, plane); + collect_faces(m_octree->child(node, 2), dimension, true, faces, pl2); + collect_faces(m_octree->child(node, 4), dimension, true, faces, pl3); + collect_faces(m_octree->child(node, 6), dimension, true, faces, pl4); + break; + case 1://0145 + collect_faces(m_octree->child(node, 0), dimension, true, faces, plane); + collect_faces(m_octree->child(node, 1), dimension, true, faces, pl2); + collect_faces(m_octree->child(node, 4), dimension, true, faces, pl3); + collect_faces(m_octree->child(node, 5), dimension, true, faces, pl4); + break; + case 2://0123 + collect_faces(m_octree->child(node, 0), dimension, true, faces, plane); + collect_faces(m_octree->child(node, 1), dimension, true, faces, pl2); + collect_faces(m_octree->child(node, 2), dimension, true, faces, pl3); + collect_faces(m_octree->child(node, 3), dimension, true, faces, pl4); + break; + } + else + switch (dimension) { + case 0://1357 + collect_faces(m_octree->child(node, 1), dimension, false, faces, plane); + collect_faces(m_octree->child(node, 3), dimension, false, faces, pl2); + collect_faces(m_octree->child(node, 5), dimension, false, faces, pl3); + collect_faces(m_octree->child(node, 7), dimension, false, faces, pl4); + break; + case 1://3467 + collect_faces(m_octree->child(node, 2), dimension, false, faces, plane); + collect_faces(m_octree->child(node, 3), dimension, false, faces, pl2); + collect_faces(m_octree->child(node, 6), dimension, false, faces, pl3); + collect_faces(m_octree->child(node, 7), dimension, false, faces, pl4); + break; + case 2://4567 + collect_faces(m_octree->child(node, 4), dimension, false, faces, plane); + collect_faces(m_octree->child(node, 5), dimension, false, faces, pl2); + collect_faces(m_octree->child(node, 6), dimension, false, faces, pl3); + collect_faces(m_octree->child(node, 7), dimension, false, faces, pl4); + break; + } + + bool same = plane == pl2; + same = (same && plane == pl3); + same = (same && plane == pl4); + if (!same) { + std::cout << "collect_faces: different plane, node: " << node << " lower: " << lower << std::endl; + From_exact from_exact; + std::cout << from_exact(plane) << std::endl; + std::cout << from_exact(pl2) << " child: " << m_octree->child(node, 4) << std::endl; + std::cout << from_exact(pl3) << " child: " << m_octree->child(node, 6) << std::endl; + std::cout << from_exact(pl4) << " child: " << m_octree->child(node, 7) << std::endl << std::endl; + } + } + } + + void collect_opposing_faces(Octree_node node, std::size_t dimension, std::vector& lower, std::vector& upper, typename Intersection_kernel::Plane_3 &plane) { + // Nothing to do for a leaf node. + if (m_octree->is_leaf(node)) + return; + + typename Intersection_kernel::Plane_3 pl[7]; + switch (dimension) { + case 0: + collect_faces(m_octree->child(node, 0), dimension, false, lower, plane); + collect_faces(m_octree->child(node, 2), dimension, false, lower, pl[0]); + collect_faces(m_octree->child(node, 4), dimension, false, lower, pl[1]); + collect_faces(m_octree->child(node, 6), dimension, false, lower, pl[2]); + collect_faces(m_octree->child(node, 1), dimension, true, upper, pl[3]); + collect_faces(m_octree->child(node, 3), dimension, true, upper, pl[4]); + collect_faces(m_octree->child(node, 5), dimension, true, upper, pl[5]); + collect_faces(m_octree->child(node, 7), dimension, true, upper, pl[6]); + break; + case 1: + collect_faces(m_octree->child(node, 0), dimension, false, lower, plane); + collect_faces(m_octree->child(node, 1), dimension, false, lower, pl[0]); + collect_faces(m_octree->child(node, 4), dimension, false, lower, pl[1]); + collect_faces(m_octree->child(node, 5), dimension, false, lower, pl[2]); + collect_faces(m_octree->child(node, 3), dimension, true, upper, pl[3]); + collect_faces(m_octree->child(node, 2), dimension, true, upper, pl[4]); + collect_faces(m_octree->child(node, 6), dimension, true, upper, pl[5]); + collect_faces(m_octree->child(node, 7), dimension, true, upper, pl[6]); + break; + case 2: + collect_faces(m_octree->child(node, 0), dimension, false, lower, plane); + collect_faces(m_octree->child(node, 1), dimension, false, lower, pl[0]); + collect_faces(m_octree->child(node, 2), dimension, false, lower, pl[1]); + collect_faces(m_octree->child(node, 3), dimension, false, lower, pl[2]); + collect_faces(m_octree->child(node, 4), dimension, true, upper, pl[3]); + collect_faces(m_octree->child(node, 5), dimension, true, upper, pl[4]); + collect_faces(m_octree->child(node, 6), dimension, true, upper, pl[5]); + collect_faces(m_octree->child(node, 7), dimension, true, upper, pl[6]); + break; + } + + From_exact from_exact; + //std::cout << from_exact(plane) << std::endl; + + bool same = true; + for (std::size_t i = 0; i < 3; i++) + same = (same && plane == pl[i]); + + for (std::size_t i = 3; i < 7; i++) + same = (same && plane.opposite() == pl[i]); + + if (!same) { + std::cout << "collect_opposing_faces: different plane, node: " << node << std::endl; + std::cout << from_exact(plane) << std::endl; + for (std::size_t i = 0; i < 3; i++) + std::cout << from_exact(pl[i]) << std::endl; + for (std::size_t i = 3; i < 7; i++) + std::cout << from_exact(pl[i].opposite()) << std::endl; + bool diff = (plane.b() == pl[6].opposite().b()); + std::cout << diff << std::endl; + std::cout << std::endl; + } + } + + bool can_add_volume_to_lcc(std::size_t volume, const std::vector& added_volumes, const std::map &vtx2index, const std::vector& added_vertices) const { + std::set vertices_of_volume; + std::vector faces_of_volume; + faces(volume, std::back_inserter(faces_of_volume)); + + for (std::size_t i = 0; i < faces_of_volume.size(); i++) { + std::vector vtx; + auto n = neighbors(faces_of_volume[i]); + int other = (n.first == static_cast(volume)) ? n.second : n.first; + if (other < 0 || !added_volumes[other]) + continue; + vertex_indices(faces_of_volume[i], std::back_inserter(vtx)); + + for (std::size_t j = 0; j < vtx.size(); j++) + vertices_of_volume.insert(vtx[j]); + } + + for (std::size_t i = 0; i < faces_of_volume.size(); i++) { + auto n = neighbors(faces_of_volume[i]); + int other = (n.first == static_cast(volume)) ? n.second : n.first; + if (other >= 0 && added_volumes[other]) + continue; + std::vector vtx; + vertex_indices(faces_of_volume[i], std::back_inserter(vtx)); + + for (std::size_t j = 0; j < vtx.size(); j++) { + auto it = vtx2index.find(vtx[j]); + assert(it != vtx2index.end()); + if (vertices_of_volume.find(vtx[j]) == vertices_of_volume.end() && added_vertices[it->second]) + return false; + } + } + + return true; + } + + CGAL::Aff_transformation_3 get_obb2abb(const std::vector > &polys) const { + std::vector pts2d; + std::size_t size = 0; + + for (std::size_t i = 0; i < polys.size(); i++) + size += polys[i].size(); + pts2d.reserve(size); + + FT minz = (std::numeric_limits::max)(), maxz = -(std::numeric_limits::max)(); + for (std::size_t i = 0; i < polys.size(); i++) + for (std::size_t j = 0; j < polys[i].size(); j++) { + pts2d.push_back(Point_2(polys[i][j].x(), polys[i][j].y())); + minz = (std::min)(minz, polys[i][j].z()); + maxz = (std::max)(maxz, polys[i][j].z()); + } + + std::vector ch; + CGAL::convex_hull_2(pts2d.begin(), pts2d.end(), std::back_inserter(ch)); + + std::vector bbox; + bbox.reserve(4); + CGAL::min_rectangle_2(ch.begin(), ch.end(), std::back_inserter(bbox)); + + Vector_2 axis1 = bbox[0] - bbox[1]; + Vector_2 axis2 = bbox[1] - bbox[2]; + FT la = CGAL::approximate_sqrt(axis1.squared_length()); + axis1 = axis1 * (1.0 / la); + FT lb = CGAL::approximate_sqrt(axis2.squared_length()); + axis2 = axis2 * (1.0 / lb); + + if (CGAL::abs(axis1.x()) < CGAL::abs(axis2.x())) { + Vector_2 tmp = axis1; + axis1 = axis2; + axis2 = tmp; + } + + if (0 > axis1.x()) + axis1 = -axis1; + + axis2 = Vector_2(-axis1.y(), axis1.x()); + + CGAL::Aff_transformation_3 R(axis1.x(), axis1.y(), 0, + -axis1.y(), axis1.x(), 0, + 0, 0, 1.0); + + CGAL::Aff_transformation_3 T(CGAL::TRANSLATION, -Vector_3((bbox[0].x() + bbox[2].x()) * 0.5, (bbox[0].y() + bbox[2].y()) * 0.5, (maxz + minz) * 0.5)); + + return R * T; + } + + bool same_face(const Face_handle& a, const Face_handle& b) const { + return (b->info().idA2 == a->info().idA2 && b->info().idB2 == a->info().idB2); + } + + void set_face(const Index& f, const Index& other, std::set& replaced, const std::vector& polygon) { + From_exact from_exact; + auto pair = replaced.insert(f); + std::size_t idx; + assert(m_partition_nodes[f.first].face_neighbors[f.second].first.first == f.first); + std::size_t vol_idx = m_partition_nodes[f.first].face_neighbors[f.second].first.second; + + if (!pair.second) { + // New face has a new index + idx = m_partition_nodes[f.first].face2vertices.size(); + // Add face into vector + m_partition_nodes[f.first].face2vertices.push_back(std::vector()); + m_partition_nodes[f.first].m_data->face_is_part_of_input_polygon().push_back(m_partition_nodes[f.first].m_data->face_is_part_of_input_polygon()[f.second]); + // Add face index into volume + m_partition_nodes[f.first].m_data->volumes()[vol_idx].faces.push_back(idx); + // Copy neighbor from already existing face + m_partition_nodes[f.first].face_neighbors.push_back(m_partition_nodes[f.first].face_neighbors[f.second]); + m_partition_nodes[f.first].m_data->face_to_support_plane().push_back(m_partition_nodes[f.first].m_data->face_to_support_plane()[f.second]); + } + else { + idx = f.second; + // All boundary faces should have a negative second neighbor. + assert(m_partition_nodes[f.first].face_neighbors[idx].second.second >= std::size_t(-6)); + } + std::vector& vertices = m_partition_nodes[f.first].face2vertices[idx]; + // First neighbor of other face should point to the inside volume in the other partition and thus cannot be negative + assert(m_partition_nodes[other.first].face_neighbors[other.second].first.second < std::size_t(-6)); + m_partition_nodes[f.first].face_neighbors[idx].second = m_partition_nodes[other.first].face_neighbors[other.second].first; + vertices.resize(polygon.size()); + for (std::size_t i = 0; i < polygon.size(); i++) { + VI& vi = polygon[i]->info(); + // Is this check actually meaningless as partition indices now start at 0? + // Check whether they are initialized as 0 and where it is used as indicator for something. +/* + if (vi.idA2.first == 0 || vi.idB2.first == 0) { + std::cout << "invalid vertex id" << std::endl; + }*/ + if (vi.idA2.first < vi.idB2.first) + vertices[i] = vi.idA2; + else if (vi.idB2.first != static_cast(-1)) + vertices[i] = vi.idB2; + else { + std::size_t vidx = m_partition_nodes[f.first].m_data->vertices().size(); + m_partition_nodes[f.first].m_data->vertices().push_back(from_exact(vi.point_3)); + m_partition_nodes[f.first].m_data->exact_vertices().push_back(vi.point_3); + vertices[i] = vi.idA2 = std::make_pair(f.first, vidx); + } + } + } + + void adapt_faces(const CDTplus& cdt) { + std::set replacedA, replacedB; + + std::size_t extracted = 0; + for (typename CDTplus::Face_handle fh : cdt.finite_face_handles()) { + // when extracting each face, I only need to insert vertices, that don't exist on either side. Otherwise, I can just reference the vertex in the other partition. + // using cit->info().id2.first as visited flag. -1 means not visited + if (fh->info().id2.first != static_cast(-1)) + continue; + + // 4 different cases: no border edge, 1, 2 or 3 + // Check 1, 2, 3 + // if first is not, continue + // if first move in other direction? search start + + // Easier approach, don't make a list of edges, but a list of vertices + // Find first pair of vertices, then just loop around last vertex using Face_circulator + // -> Triangulation only has vertices and faces, no easy way to loop over edges + + std::vector face; + + for (std::size_t i = 0; i < 3; i++) + if (cdt.is_infinite(fh->neighbor(static_cast(i))) || !same_face(fh, fh->neighbor(static_cast(i)))) { + face.push_back(fh->vertex((i + 2) % 3)); + face.push_back(fh->vertex((i + 1) % 3)); + break; + } + + // No border edge? + if (face.empty()) + continue; + else { + //dump_point(face.back(), "last.xyz"); + Face_handle last = fh; + + // Mark seed face as segmented + fh->info().id2.first = extracted; + + // edge is pair + while (face.front() != face.back()) { + auto eit = cdt.incident_edges(face.back(), last); + auto first = eit; + + assert(!cdt.is_infinite(eit->first)); + do { + // Export tri + + //dump_point(eit->first->vertex(eit->second), "p.xyz"); + //dump_face(eit->first, "tri.polylines.txt"); + + // Is the current edge to the infinite vertex? + if (cdt.is_infinite(eit->first->neighbor((eit->second + 1) % 3))) { + eit++; + continue; + } + + bool infinite = cdt.is_infinite(eit->first); + + if (infinite || !same_face(last, eit->first)) { + last = eit->first->neighbor((eit->second + 1) % 3); + last->info().id2.first = extracted; + face.push_back(eit->first->vertex(eit->second)); + + break; + } + eit++; + assert(eit != first); + } while (eit != first); + // If last vertex is equal to first vertex, stop + // Take last vertex and face + // First find index of vertex in that face + // Check if opposite face of next edge, if not same, add next vertex and reloop + // if not, check next face + + assert(face.size() < 100); + } + + // The last vertex is equal to the first one, so it should be removed. + face.pop_back(); + + // face ids in partitions are stored in fh->info + ID& id = fh->info(); + set_face(id.idA2, id.idB2, replacedA, face); + set_face(id.idB2, id.idA2, replacedB, face); + } + + // Checking for border edges. If opposite faces do not exist or don't have the same indices, the edge belongs to a new face. + // cit->neighbor(i) is the face opposite of vertex(i), meaning on the other side of the edge between vertex((i+1)%3) and vertex((i+2)%3) + } + } + + std::pair find_portal(std::size_t volume, std::size_t former, const Index& vA, const Index& vB, std::size_t& portal) const { + portal = static_cast(-7); + auto vol = m_volumes[volume]; + std::vector& faces = m_partition_nodes[vol.first].m_data->volumes()[vol.second].faces; + + for (std::size_t f = 0; f < faces.size(); f++) { + auto n = neighbors(std::make_pair(vol.first, faces[f])); + if (n.first == static_cast(former) || n.second == static_cast(former)) + continue; + + std::size_t idxA = static_cast(-1); + std::size_t numVtx = m_partition_nodes[vol.first].face2vertices[faces[f]].size(); + for (std::size_t v = 0; v < numVtx; v++) + if (m_partition_nodes[vol.first].face2vertices[faces[f]][v] == vA) { + idxA = v; + break; + } + // If vertex wasn't found, skip to next face. + if (idxA == static_cast(-1)) + continue; + + std::size_t idxB = static_cast(-1); + int dir = 0; + if (m_partition_nodes[vol.first].face2vertices[faces[f]][(idxA + 1) % numVtx] == vB) { + dir = 1; + idxB = (idxA + 1) % numVtx; + } + else if (m_partition_nodes[vol.first].face2vertices[faces[f]][(idxA + numVtx - 1) % numVtx] == vB) { + dir = -1; + idxB = (idxA + numVtx - 1) % numVtx; + } + + // If only the first vertex was found, it is just an adjacent face. + if (idxB == static_cast(-1)) + continue; + + // Edge found + // Save portal face for next volume. + portal = f; + + return std::make_pair(idxA, dir); + } + return std::make_pair(-1, -1); + } + + void adapt_internal_edges(const CDTplus& cdtC, const std::vector &faces_node, std::vector >& c) { + assert(faces_node.size() == c.size()); + + //std::size_t not_skipped = 0; + + for (std::size_t f = 0; f < c.size(); f++) { + std::vector faces_of_volume; + // The face index is probably no longer valid and the full face has been replaced by a smaller face using merged indices + // Each constraint has a volume. + // Constraints of the same volume are subsequent + for (std::size_t e = 0; e < c[f].size(); e++) { + auto id = c[f][e].id_single; + if (id == 0) + continue; + + id = (c[f][e].id_merged != 0) ? c[f][e].id_merged : id; + id = (c[f][e].id_overlay != 0) ? c[f][e].id_overlay : id; + + int volume = static_cast(c[f][e].volume); + + //auto it = (c[f][e].vA < c[f][e].vB) ? constraint2edge.find(std::make_pair(c[f][e].vA, c[f][e].vB)) : constraint2edge.find(std::make_pair(c[f][e].vB, c[f][e].vA)); + + // Extract edge + std::vector vertices_of_edge; + for (typename CDTplus::Vertices_in_constraint_iterator vi = cdtC.vertices_in_constraint_begin(id); vi != cdtC.vertices_in_constraint_end(id); vi++) { + if ((*vi)->info().idA2.first == static_cast(-1)) + vertices_of_edge.push_back((*vi)->info().idB2); + else vertices_of_edge.push_back((*vi)->info().idA2); + } + + // Not necessary, as I am replacing vertices anyway? + if (vertices_of_edge.size() == 2) + continue; + + //not_skipped++; + + // Check length of constraint + // size 2 means it has not been split, thus there are no t-junctions. + assert (vertices_of_edge.size() >= 2); + + faces_of_volume.clear(); + faces(volume, std::back_inserter(faces_of_volume)); + + int starting_volume = volume; + + std::size_t idx, idx2; + auto p = find_portal(volume, -7, c[f][e].vA, c[f][e].vB, idx); + + if (idx == static_cast(-7)) { + continue; + } + auto n = neighbors(faces_of_volume[idx]); + int other = (n.first == volume) ? n.second : n.first; + auto p2 = find_portal(volume, other, c[f][e].vA, c[f][e].vB, idx2); + + // For cdtA, there should be two portals and for cdtB only one + // How to discard the traversing one? + if (idx != static_cast(-7)) { + // Check if the portal idx is traversing. + // The neighbors of a portal can be negative if it is not in the current face between the octree nodes. + + if (idx2 < static_cast(-7) && m_volumes[volume].first != m_volumes[other].first) { + idx = idx2; + p = p2; + } + } + else { + idx = idx2; + p = p2; + } + if (idx == static_cast(-7)) + continue; + + std::vector tmp = m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second]; + + // Insert vertices in between + if (p.second == 1) + for (std::size_t i = 1; i < vertices_of_edge.size() - 1; i++) + m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].insert(m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].begin() + p.first + i, vertices_of_edge[i]); + else + for (std::size_t i = 1; i < vertices_of_edge.size() - 1; i++) + m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].insert(m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].begin() + p.first, vertices_of_edge[i]); + + + n = neighbors(faces_of_volume[idx]); + + if (n.first != volume && n.second != volume) + std::cout << "portal does not belong to volume" << std::endl; + volume = (n.first == volume) ? n.second : n.first; + int former = (idx == idx2) ? -1 : static_cast(idx2); + + while (volume >= 0 && volume != starting_volume) { // What are the stopping conditions? There are probably several ones, e.g., arriving at the starting volume, not finding a portal face + faces_of_volume.clear(); + faces(volume, std::back_inserter(faces_of_volume)); + + auto p = find_portal(volume, former, c[f][e].vA, c[f][e].vB, idx); + + if (idx == static_cast(-7)) + break; + + // Insert vertices in between + if (p.second == 1) + for (std::size_t i = 1; i < vertices_of_edge.size() - 1; i++) + m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].insert(m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].begin() + p.first + i, vertices_of_edge[i]); + else + for (std::size_t i = 1; i < vertices_of_edge.size() - 1; i++) + m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].insert(m_partition_nodes[faces_of_volume[idx].first].face2vertices[faces_of_volume[idx].second].begin() + p.first, vertices_of_edge[i]); + + + // This is redundant to get next? + auto n = neighbors(faces_of_volume[idx]); + + if (n.first != volume && n.second != volume) + std::cout << "portal does not belong to volume" << std::endl; + volume = (n.first == volume) ? n.second : n.first; + + former = volume; + } + } + } + } + + void make_conformal(std::vector& a, std::vector& b, typename Intersection_kernel::Plane_3& plane) { + std::unordered_map > a_sets, b_sets; + for (const Index& i : a) + a_sets[i.first].push_back(i); + for (const Index& i : b) + b_sets[i.first].push_back(i); + + // At first, one CDTplus is created for each partition node + std::vector a_cdts(a_sets.size()), b_cdts(b_sets.size()); + + std::vector< std::vector > > a_constraints; + std::vector< std::vector > > b_constraints; + + std::map point_mapping; + + std::size_t idx = 0; + a_constraints.resize(a_sets.size()); + + std::set partitions; + for (auto& p : a_sets) { + partitions.insert(p.first); + build_cdt(a_cdts[idx], p.second, a_constraints[idx], plane); + + idx++; + } + + idx = 0; + b_constraints.resize(b_sets.size()); + for (auto& p : b_sets) { + partitions.insert(p.first); + build_cdt(b_cdts[idx], p.second, b_constraints[idx], plane); + + idx++; + } + + CDTplus cdtA, cdtB, cdtC; + build_cdt(cdtA, a_cdts, a_constraints, plane); + + build_cdt(cdtB, b_cdts, b_constraints, plane); + + overlay(cdtC, cdtA, a_constraints, cdtB, b_constraints, plane); + + adapt_faces(cdtC); + + idx = 0; + for (auto& p : a_sets) { + adapt_internal_edges(cdtC, p.second, a_constraints[idx]); + idx++; + } + + idx = 0; + for (auto& p : b_sets) { + adapt_internal_edges(cdtC, p.second, b_constraints[idx]); + idx++; + } + } + + void make_conformal(Octree_node node) { + // pts2index maps exact points to their indices with one unique index. + // index_map maps indices to unique indices. Used to map the points inside a partition to a unique index. + + // Nothing to do for a leaf node. + if (m_octree->is_leaf(node)) + return; + + // Make childs conformal + for (std::size_t i = 0; i < 8; i++) + make_conformal(m_octree->child(node, i)); + + // Make itself conformal + // Get faces between child nodes + // do in inverse dimension order (like inverse splitting order, start by 2 or 1 and walk down to 0) + // follow cdt approach in split_octree + + // Order of children? + // x, y, z planes can be merged independently + for (std::size_t dim = 0; dim < 3; dim++) { + std::vector lower, upper; + typename Intersection_kernel::Plane_3 plane; + + collect_opposing_faces(node, dim, lower, upper, plane); + + make_conformal(lower, upper, plane); + + } + } + + void split_octree() { + // Octree creation for sub partition + std::size_t count = 0; + for (const auto& p : m_input_polygons) + count += p.size(); + + m_points.clear(); + m_points.reserve(count); + m_polygons.reserve(m_input_polygons.size()); + + To_exact to_exact; + From_exact from_exact; + + if (m_parameters.reorient_bbox) { + m_transform = to_exact(get_obb2abb(m_input_polygons)); + + for (const auto& p : m_input_polygons) { + std::size_t idx = m_points.size(); + for (const Point_3& pt : p) + m_points.push_back(from_exact(m_transform.transform(to_exact(pt)))); + + m_polygons.push_back(std::vector(p.size())); + std::iota(m_polygons.back().begin(), m_polygons.back().end(), idx); + } + } + else { + m_transform = CGAL::Aff_transformation_3(CGAL::IDENTITY); + + for (const auto& p : m_input_polygons) { + std::size_t idx = m_points.size(); + std::copy(p.begin(), p.end(), std::back_inserter(m_points)); + m_polygons.push_back(std::vector(p.size())); + std::iota(m_polygons.back().begin(), m_polygons.back().end(), idx); + } + } + + m_octree = std::make_unique(CGAL::Orthtree_traits_polygons(m_points, m_polygons, m_parameters.bbox_dilation_ratio)); + m_octree->refine(m_parameters.max_octree_depth, m_parameters.max_octree_node_size); + + std::size_t leaf_count = 0; + std::size_t max_count = 0; + + for (typename Octree::Node_index node : m_octree->traverse(CGAL::Orthtrees::Leaves_traversal(*m_octree))) { + if (m_octree->is_leaf(node)) + leaf_count++; + else + std::cout << "Leaves_traversal traverses non-leaves" << std::endl; + max_count = (std::max)(max_count, node); + } + + m_partition_nodes.resize(leaf_count); + + m_node2partition.resize(max_count + 1, std::size_t(-1)); + + std::size_t idx = 0; + CGAL::Aff_transformation_3 inv = m_transform.inverse(); + for (typename Octree::Node_index node : m_octree->traverse(CGAL::Orthtrees::Leaves_traversal(*m_octree))) + if (m_octree->is_leaf(node)) { + // Creating bounding box + CGAL::Iso_cuboid_3 box = m_octree->bbox(node); + m_partition_nodes[idx].bbox[0] = typename Intersection_kernel::Point_3(box.xmin(), box.ymin(), box.zmin()); + m_partition_nodes[idx].bbox[1] = typename Intersection_kernel::Point_3(box.xmax(), box.ymin(), box.zmin()); + m_partition_nodes[idx].bbox[2] = typename Intersection_kernel::Point_3(box.xmax(), box.ymax(), box.zmin()); + m_partition_nodes[idx].bbox[3] = typename Intersection_kernel::Point_3(box.xmin(), box.ymax(), box.zmin()); + m_partition_nodes[idx].bbox[4] = typename Intersection_kernel::Point_3(box.xmin(), box.ymax(), box.zmax()); + m_partition_nodes[idx].bbox[5] = typename Intersection_kernel::Point_3(box.xmin(), box.ymin(), box.zmax()); + m_partition_nodes[idx].bbox[6] = typename Intersection_kernel::Point_3(box.xmax(), box.ymin(), box.zmax()); + m_partition_nodes[idx].bbox[7] = typename Intersection_kernel::Point_3(box.xmax(), box.ymax(), box.zmax()); + + if (m_parameters.reorient_bbox) + for (std::size_t i = 0; i < 8; i++) + m_partition_nodes[idx].bbox[i] = inv.transform(m_partition_nodes[idx].bbox[i]); + + // Get consistent Plane_3 from Octree to generate exact planes + + auto polys = m_octree->data(node); + for (std::size_t j = 0; j < polys.size(); j++) { + m_partition_nodes[idx].input_polygons.push_back(polys[j].first); + m_partition_nodes[idx].m_input_planes.push_back(m_input_planes[polys[j].first]); + } + + m_partition_nodes[idx].clipped_polygons.resize(polys.size()); + for (std::size_t i = 0; i < polys.size(); i++) { + m_partition_nodes[idx].clipped_polygons[i].resize(polys[i].second.size()); + for (std::size_t j = 0; j < polys[i].second.size(); j++) + m_partition_nodes[idx].clipped_polygons[i][j] = from_exact(inv.transform(to_exact(polys[i].second[j]))); + } + + // set node index + m_partition_nodes[idx].node = node; + m_node2partition[node] = idx; + + if (m_parameters.debug) { + const std::string vfilename = std::to_string(idx) + "-box.polylines.txt"; + std::ofstream vout(vfilename); + vout.precision(20); + // zmin side + vout << 5; + vout << " " << m_partition_nodes[idx].bbox[0]; + vout << " " << m_partition_nodes[idx].bbox[1]; + vout << " " << m_partition_nodes[idx].bbox[2]; + vout << " " << m_partition_nodes[idx].bbox[3]; + vout << " " << m_partition_nodes[idx].bbox[0]; + // zmax side + vout << std::endl << 5; + vout << " " << m_partition_nodes[idx].bbox[4]; + vout << " " << m_partition_nodes[idx].bbox[5]; + vout << " " << m_partition_nodes[idx].bbox[6]; + vout << " " << m_partition_nodes[idx].bbox[7]; + vout << " " << m_partition_nodes[idx].bbox[4]; + // 4 edges between zmin and zmax + vout << std::endl << 2; + vout << " " << m_partition_nodes[idx].bbox[0]; + vout << " " << m_partition_nodes[idx].bbox[5]; + vout << std::endl << 2; + vout << " " << m_partition_nodes[idx].bbox[1]; + vout << " " << m_partition_nodes[idx].bbox[6]; + vout << std::endl << 2; + vout << " " << m_partition_nodes[idx].bbox[2]; + vout << " " << m_partition_nodes[idx].bbox[7]; + vout << std::endl << 2; + vout << " " << m_partition_nodes[idx].bbox[3]; + vout << " " << m_partition_nodes[idx].bbox[4]; + vout << std::endl; + vout.close(); + + //KSP_3::internal::dump_polygons(m_partition_nodes[idx].clipped_polygons, std::to_string(idx) + "-polys.ply"); + } + idx++; + } + + if (m_parameters.verbose) + std::cout << "input split into " << m_partition_nodes.size() << " partitions" << std::endl; + } +}; + +} // namespace CGAL + +#endif // CGAL_KINETIC_SPACE_PARTITION_3_H diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/copyright.txt b/Kinetic_space_partition/package_info/Kinetic_space_partition/copyright.txt new file mode 100644 index 00000000000..d01540d2521 --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/copyright.txt @@ -0,0 +1,2 @@ +GeometryFactory SARL (France) +INRIA Sophia-Antipolis \ No newline at end of file diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/dependencies b/Kinetic_space_partition/package_info/Kinetic_space_partition/dependencies new file mode 100644 index 00000000000..737b0d92b95 --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/dependencies @@ -0,0 +1,49 @@ +Algebraic_foundations +Arithmetic_kernel +Arrangement_on_surface_2 +BGL +Boolean_set_operations_2 +Bounding_volumes +CGAL_Core +Cartesian_kernel +Circulator +Combinatorial_map +Convex_hull_2 +Convex_hull_3 +Distance_2 +Distance_3 +Filtered_kernel +Generalized_map +HalfedgeDS +Hash_map +Homogeneous_kernel +Installation +Intersections_2 +Intersections_3 +Interval_support +Kernel_23 +Kernel_d +Kinetic_space_partition +Linear_cell_complex +Modular_arithmetic +Number_types +Optimal_bounding_box +Orthtree +Point_set_3 +Point_set_processing_3 +Polygon +Polygon_mesh_processing +Principal_component_analysis +Principal_component_analysis_LGPL +Profiling_tools +Property_map +Random_numbers +STL_Extension +Solver_interface +Spatial_sorting +Stream_support +Surface_mesh +Surface_sweep_2 +TDS_2 +Triangulation_2 +Union_find diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/description.txt b/Kinetic_space_partition/package_info/Kinetic_space_partition/description.txt new file mode 100644 index 00000000000..f1a7576f3cb --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/description.txt @@ -0,0 +1,4 @@ +Kinetic Shape Partition + +This CGAL package provides a way to partition 2D or 3D space by propagating +2D segments or 3D polygons until they interesect the predefined number of times. diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/license.txt b/Kinetic_space_partition/package_info/Kinetic_space_partition/license.txt new file mode 100644 index 00000000000..8bb8efcb72b --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/long_description.txt b/Kinetic_space_partition/package_info/Kinetic_space_partition/long_description.txt new file mode 100644 index 00000000000..520f26605bf --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/long_description.txt @@ -0,0 +1,6 @@ +Kinetic Shape Partition + +This CGAL package provides a way to partition 2D or 3D space by propagating +2D segments or 3D polygons until they intersect the predefined number of times. +Once the partion is found, a 3D shape can be reconstructed by utilizing a graph cut approach. +The final result is a piece-wise linear approximation of the given smooth shape. diff --git a/Kinetic_space_partition/package_info/Kinetic_space_partition/maintainer b/Kinetic_space_partition/package_info/Kinetic_space_partition/maintainer new file mode 100644 index 00000000000..2caaed5e3ce --- /dev/null +++ b/Kinetic_space_partition/package_info/Kinetic_space_partition/maintainer @@ -0,0 +1 @@ +Sven Oesau diff --git a/Kinetic_space_partition/readme.md b/Kinetic_space_partition/readme.md new file mode 100644 index 00000000000..b654465de42 --- /dev/null +++ b/Kinetic_space_partition/readme.md @@ -0,0 +1,193 @@ +** GENERAL ** + +All the test data are placed in the folder examples/data. The name of the folder indicates the type of data or its complexity. +The complexity 1 is low while the complexity 6 is high. + +Examples are the entry point to the package: +- kinetic_2d_example: 2D kinetic algorithm on a random set of segments +- kinetic_precomputed_shapes_example: 3D kinetic algorithm on a set of user-defined polygons read from a file +- kinetic_random_shapes_example: 3D kinetic algorithm on a set of random polygons, you can provide the number + of input polygons to be generated and the number of vertices each polygon should have +- kinetic_reconstruction_example: given a ply with classified point cloud, it first fits polygons using Region Growing, + then runs 3D kinetic, and finally filters out exterior volumes creating a reconstructed model + +Tests: +- kinetic_2d_stress_test: tests the 2D kinetic algorithm +- kinetic_3d_test_all: tests the 3D kinetic algorithm on all data from the examples folder + +The 3D algorithm is running on macOS with zero warnings. On Windows and Linux, it compiles and works, +but can generate warnings related to conversions between std:size_t and int e.g. or similar warnings. +The 2D algorithm should work on all platforms as well. + + +** CURRENT ISSUES ** + + +-- EPICK versus EPECK -- + +By running: +./kinetic_precomputed_shapes_example data/stress-test-4/test-9-rnd-polygons-12-4.off + +first with EPICK and then with EPECK shows a huge difference in runtime. This +data set contains 12 random polygons, each having 4 vertices. The time for EPICK is +milliseconds while for EPECK is about 3 minutes. It can also be noticed that most of +the time is spent at the last iterations while the first iterations are very fast. +It is even slower for `Simple_cartesian`. + +It is probably happening because at the latest iterations the computation involves +all operations carried out from the first iteration. Evaluating these cascading operations +is a slow process. E.g. computing an intersection between two lines at the first iterations +takes seconds while at the higher iterations it takes minutes. + +Another issue shows up when running the code with the following data set: +./kinetic_precomputed_shapes_example data/real-data-test/test-40-polygons.ply 6 +that is with k = 6, where k is the number of allowed intersections between support planes +of the input polygons. Here, at about 5300 iteration, assertions start failing but not because +some parts of the algorithm are not implemented (as indicated in the TODO) but because +the scaling is no longer uniform due to the accumulating errors. It leads to wrong configurations +and hence to the wrong events, which in practice with the correct precision cannot happen. + + +-- Possible solutions -- + +- Use EPICK and compute always with respect to the input. E.g. intersections between lines should be +done not between lines at the current and previous iterations but between lines at the current +and first iterations. The reason for this optimization is that if we use simply EPICK, +when the number of input polygons grow, we bump into an issue of the accumulating error that gets +bigger and bigger with each iteration and at some point can break the results. It does not happen +with EPECK but we lose speed there. + +- Use EPECK only when it is absolutely necessary like when computing intersections and +use EPICK for all other computations. This way we avoid accumulating errors and should +preserve speed. + +A few ideas shortly after the meeting with Sebastien: +- speed up kinetic with EPECK by optimizing the parts, which are slow, vtune it +- use different speed for each polygon edge during the uniform scaling, a similar + trick to what is used in the straight skeleton now +- point_2() wrapper inside Support_plane.h: it can compute point not based on the point constructed + at the previous event (which is cascading) but based on the interesting polygon edge and intersection graph edge +- avoid certain events in the queue or keep track only of the last 10 events instead of all of them + + +** INTERNALS ** + + +-- File descriptions -- + +- KSR sub-folder, used in both KSR2 and KSR3: + + - conversions.h: the kinetic_traits class that performs intersections, all intersections + in the code are called from this class, here the hybrid mode could be potentially implemented. + + - debug.h: a file with a bunch of functions which enable to export / dump to a file + different intermediate steps, events, data structure, etc. + + - enum.h: enumerations used by the reconstruction code from the Reconstruction.h. + + - parameters.h: internal parameters used in the code. + + - property_map.h: property maps used by the reconstruction code from the Reconstruction.h. + + - utils.h: different internal utilities such as normals, distances, angles, etc. + the most important one is tolerance(): this is a global tolerance used everywhere in the code + +- KSR_2 sub-folder, 2D kinetic algorithm, works and tested, fully implemented by Simon. + +- KSR_3 sub-folder, 3D kinetic algorithm + 3D reconstruction algorithm: + + - Data_structure.h: a class with all conversions and all basic operations, which are + performed on the polygons and during events, it also stores the main intersection graph + and all support planes. + + - Event_queue.h: a wrapper around boost multi_index_container that represents a queue of + all events, which can be sorted by time or vertex type. It is based on doubles so even + when we use EPECK globally, we need to convert to double here because boost multi_index_container + fails to work with EPECK due to the fact that values represented by EPECK can vary when converted + to_double() or to_interval(). + + - Event.h: represents different event types used in the propagation. + + - Intersection_graph.h: a boost adjacency_list graph that stores an initial intersection graph + fully in 3D that is used as constraints for kinetic propagation. + + - Support_plane.h: a wrapper around a support plane for each input polygon that stores a 2D + surface mesh that represents an input polygon. So, initially this mesh has only 1 face that is + input polygon while during propagation it is updated and new vertices, faces are added. We preserve + the uniform scaling of the input polygon and validity of this mesh after each event. If any of these + two fails, the whole algorithm fails. At the end of the support plane header, there is an overload + of the operator()== that is used to compare if two planes are equal. It heavily depends on the + tolerance parameters and in case two planes are found to be equal, they are merged at the initialization step. + + - Initializer.h: a class that gets input polygons, creates an enlarged bounding box, removes all + near-collinear vertices of each polygon, merges all near-coplanar support planes, then inserts each + support plane and intersects it with the bounding box. At the final step, it calls Polygon_splitter + class in order to intersect all polygons within the bounding box, one support plane at a time. + + - Polygon_splitter.h: given a support plane, its original polygon, and a set of intersection edges created + by intersecting all support planes with the bounding box (see Initializer.h), it builds a CDT, inserts all these edges + in the CDT, marks all interior and exterior faces and creates a proper 2D surface mesh. This class can be parameterized + by any kernel independently of the input kernel. + + - Propagation.h: is called after Initializer.h has done its work, this class creates an initial queue of + events for all vertices of all polygons and handles these events one by one. This is the most time-consuming + part of the total algorithm. The queue is updated and rebuilt until no valid events show up. This class can be parameterized + by any kernel independently of the input kernel. + + - Finalizer.h: is called after Propagation.h, this class receives a set of 2D surface meshes from the propagation + and an initial intersection graph and does three things: first it checks the validity of the results, it then searches + for dangling / hanging faces if any and fills the gaps; and finally creates 3D volumes bounded by all faces of the 2D surface meshes. + This class can be parameterized by any kernel independently of the input kernel. + + - Reconstruction.h: this class first gets a point cloud with or without semantic labels. If the labels are missing, some + parts of the code have to be still finished. However, if labels are present, it assumes they come from urban areas that is they are + walls, roofs, ground, and trees. It removes all tree points, fits a polygon to the ground points, runs region growing + separately for wall and roof points and detects convex planar polygons, which approximate the input point cloud. + Next, it runs 3D kinetic on these input polygons + ground polygon and gets a set of volumes, which partition the 3D space. + It then estimates a probability of each volume to be inside or outside the point cloud using Visibility.h and runs the graph cut + algorithm on these estimations using Graphcut.h. At the end, it removes all volumes, which have been labeled as exterior volumes + and returns a reconstructed model: 3D surface mesh that approximates the input point cloud (or buildings in case labels are urban related). + + - Visibility.h: estimates a probability of each partition volume to be inside or outside a point cloud by using normals + of the input points and sampling each volume. + + - Graphcut.h: takes initially estimated probabilities for each volume to be interior or exterior with respect to the point cloud, + computed by Visibility.h, creates a graph where each node is a volume and each edge connects volumes to their neighboring volumes, + and runs the mincut - maxflow Boykov optimization algorithm to define which volumes are inside and outside the point cloud. + All edges are weighted by the face area that adjacent to two incident volumes and all nodes are weighted by the volume itself. + +- Kinetic_shape_reconstruction_2.h: is an entry point to the 2D kinetic propagation. + +- Kinetic_shape_reconstruction_3.h: is an entry point to the 3D kinetic propagation and 3D kinetic reconstruction algorithms. + + +-- Epsilon usage inside the code -- + +Note that epsilon tolerance is used throughout the code. It is defined inside utils.h +in the function tolerance(). It is used everywhere where we expect a result of certain precision +but it may not be the case. We check if we outside this tolerance and apply different sub-algorithms +in order to be sure we that will generate the right results. This is mostly used for EPICK. When using EPECK, +the precision is higher and the tolerance should be satisfied until there is a bug. + + +-- Important parts of the code -- + + - point_2() wrapper from the Support_plane.h. Currently all original points are 3D, + this wrapper takes a point, and constructs the corresponding 2D point for the chosen + 2D support plane and at the chosen time step. That means all these points are constructed + that is a weak point when using EPECK because it is slow. + + - operator==() at the bottom of the Support_plane.h: controls if two near-coplanar planes should + be merged. If we merge too many planes because our input parameters are very weak, we fail to create + a valid partition. If we do not merge at all, the near-coplanar support planes may lead to intricated + errors in the kinetic propagation due to numerical instabilities. + + - parameters: all all explained in the parameters.h. The parameters used in the Reconstruction.h are defined + in the file examples/include/Parameters.h. + + - FUTURE POINTS AND DIRECTIONS section at the bottom of the Data_structure.h, this is where the future points + are computed and this is a part of the code that leads to multiple precision issues, identifying a future + point from the previous event is hard, so instead we simply translate the lines and intersect them at the next + time step to get the point at which our current vertex will be later, but these intersections are imprecise. + If we lose precision here, we fail to scale polygon uniformly so our point can end up behind the bounding box + or in the direction opposite to the one we need, especially if the lines that we intersect are near parallel. diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/CMakeLists.txt b/Kinetic_space_partition/test/Kinetic_space_partition/CMakeLists.txt new file mode 100644 index 00000000000..e062c206339 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/CMakeLists.txt @@ -0,0 +1,24 @@ +# Created by the script cgal_create_CMakeLists. +# This is the CMake script for compiling a set of CGAL applications. + +cmake_minimum_required(VERSION 3.1...3.23) + +project(Kinetic_space_partition_Tests) + +find_package(CGAL REQUIRED) +include(CGAL_CreateSingleSourceCGALProgram) + +find_package(Eigen3 3.1.0 REQUIRED) +if(Eigen3_FOUND) + message(STATUS "Found Eigen") + include(CGAL_Eigen_support) + + set(targets kinetic_3d_test_all) + + foreach(target ${targets}) + create_single_source_cgal_program("${target}.cpp") + target_link_libraries(${target} PUBLIC CGAL::Eigen_support) + endforeach() +else() + message(ERROR "This program requires the Eigen library, and will not be compiled.") +endif() diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-2-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-2-polygons.off new file mode 100644 index 00000000000..136de61f02d --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-2-polygons.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +0.0 1.0 0.0 +0.5 0.5 0.0 +0.5 1.5 0.0 +0.5 1.5 1.0 +0.5 0.5 1.0 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-4-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-4-polygons.off new file mode 100644 index 00000000000..5da6512fd57 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-4-polygons.off @@ -0,0 +1,22 @@ +OFF +16 4 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +0.0 1.0 0.0 +2.0 0.0 0.0 +3.0 0.0 0.0 +3.0 1.0 0.0 +2.0 1.0 0.0 +0.5 0.5 0.0 +0.5 1.5 0.0 +0.5 1.5 1.0 +0.5 0.5 1.0 +2.5 0.5 0.0 +2.5 1.5 0.0 +2.5 1.5 1.0 +2.5 0.5 1.0 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-5-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-5-polygons.off new file mode 100644 index 00000000000..23ac72dada0 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-5-polygons.off @@ -0,0 +1,27 @@ +OFF +20 5 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +0.0 1.0 0.0 +2.0 0.0 0.0 +3.0 0.0 0.0 +3.0 1.0 0.0 +2.0 1.0 0.0 +0.5 0.5 0.0 +0.5 1.5 0.0 +0.5 1.5 1.0 +0.5 0.5 1.0 +2.5 0.5 0.0 +2.5 1.5 0.0 +2.5 1.5 1.0 +2.5 0.5 1.0 +1.5 1.5 0.0 +2.5 2.5 0.0 +1.5 3.5 0.0 +0.5 2.5 0.0 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 +4 16 17 18 19 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-collinear.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-collinear.off new file mode 100644 index 00000000000..5f1bb379136 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-collinear.off @@ -0,0 +1,32 @@ +OFF +28 2 0 +1.00 1.00 0.0 +1.40 0.96 0.0 +1.80 0.96 0.0 +2.20 0.96 0.0 +2.60 1.00 0.0 +2.64 1.40 0.0 +2.64 1.60 0.0 +2.60 2.00 0.0 +2.20 2.03 0.0 +1.80 2.04 0.0 +1.40 2.03 0.0 +1.00 2.00 0.0 +0.96 1.60 0.0 +0.96 1.40 0.0 +1.8 1.00 1.00 +1.8 1.40 0.96 +1.8 1.80 0.96 +1.8 2.20 0.96 +1.8 2.60 1.00 +1.8 2.64 1.40 +1.8 2.64 1.60 +1.8 2.60 2.00 +1.8 2.20 2.03 +1.8 1.80 2.04 +1.8 1.40 2.03 +1.8 1.00 2.00 +1.8 0.96 1.60 +1.8 0.96 1.40 +14 0 1 2 3 4 5 6 7 8 9 10 11 12 13 +14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xy.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xy.off new file mode 100644 index 00000000000..f36cb73dce9 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xy.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 1.0 0.0 +0.0 1.0 0.0 +2.0 0.0 0.0 +3.0 0.0 0.0 +3.0 1.0 0.0 +2.0 1.0 0.0 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xz.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xz.off new file mode 100644 index 00000000000..05f6a48060c --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-xz.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +1.0 0.0 1.0 +0.0 0.0 1.0 +2.0 0.0 0.0 +3.0 0.0 0.0 +3.0 0.0 1.0 +2.0 0.0 1.0 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-yz.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-yz.off new file mode 100644 index 00000000000..8a3efc2a017 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-flat-bbox-yz.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.0 0.0 0.0 +0.0 1.0 0.0 +0.0 1.0 1.0 +0.0 0.0 1.0 +0.0 2.0 0.0 +0.0 3.0 0.0 +0.0 3.0 1.0 +0.0 2.0 1.0 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-1.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-1.off new file mode 100644 index 00000000000..9e1d446e747 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-1.off @@ -0,0 +1,33 @@ +OFF +25 6 0 +0.0 0.0 0.0 +2.3 0.0 0.0 +2.4 0.0 0.9 +0.0 0.0 1.0 +0.5 0.1 0.0 +0.5 1.1 0.0 +0.5 1.1 1.0 +0.5 0.2 1.0 +1.5 0.1 0.0 +1.5 0.01 0.75 +1.5 1.1 0.0 +1.5 1.1 1.0 +1.5 0.2 1.0 +1.52 0.01 0.5 +3.0 0.1 0.5 +3.0 1.1 0.5 +2.0 1.1 0.5 +2.5 0.2 0.0 +2.5 1.1 0.0 +2.5 1.1 1.0 +2.5 0.3 1.0 +-0.5 -0.1 0.0 +-0.5 -1.1 0.0 +-0.5 -1.1 1.0 +-0.5 -0.2 1.0 +4 0 1 2 3 +4 4 5 6 7 +5 8 9 10 11 12 +4 13 14 15 16 +4 17 18 19 20 +4 21 22 23 24 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-2.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-2.off new file mode 100644 index 00000000000..e419bd5aa1b --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-local-global-2.off @@ -0,0 +1,34 @@ +OFF +26 6 0 +0.0 0.0 0.0 +2.12 0.0 0.0 +2.1 0.0 1.0 +0.0 0.0 1.0 +0.5 0.1 0.0 +0.5 1.1 0.0 +0.5 1.1 1.0 +0.5 0.2 1.0 +1.5 0.1 0.0 +1.5 0.01 0.75 +1.5 1.1 0.0 +1.5 1.1 1.0 +1.5 0.2 1.0 +1.52 0.01 0.5 +2.4 0.02 0.5 +3.0 0.1 0.5 +3.0 1.1 0.5 +2.0 1.1 0.5 +2.5 0.2 0.0 +2.5 1.1 0.0 +2.5 1.1 1.0 +2.5 0.3 1.0 +-0.5 -0.1 0.0 +-0.5 -1.1 0.0 +-0.5 -1.1 1.0 +-0.5 -0.2 1.0 +4 0 1 2 3 +4 4 5 6 7 +5 8 9 10 11 12 +5 13 14 15 16 17 +4 18 19 20 21 +4 22 23 24 25 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-same-time.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-same-time.off new file mode 100644 index 00000000000..5c4c76a570f --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/edge-case-test/test-same-time.off @@ -0,0 +1,32 @@ +OFF +24 6 0 +0.0 0.0 0.0 +1.8 0.0 0.0 +1.8 0.0 1.0 +0.0 0.0 1.0 +0.5 0.1 0.0 +0.5 1.1 0.0 +0.5 1.1 1.0 +0.5 0.1 1.0 +1.5 0.1 0.0 +1.5 1.1 0.0 +1.5 1.1 1.0 +1.5 0.1 1.0 +2.0 0.1 0.5 +3.0 0.1 0.5 +3.0 1.1 0.5 +2.0 1.1 0.5 +2.5 0.2 0.0 +2.5 1.1 0.0 +2.5 1.1 1.0 +2.5 0.2 1.0 +-0.5 -0.1 0.0 +-0.5 -1.1 0.0 +-0.5 -1.1 1.0 +-0.5 -0.1 1.0 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 +4 16 17 18 19 +4 20 21 22 23 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-10-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-10-polygons.off new file mode 100644 index 00000000000..ad703a64d3f --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-10-polygons.off @@ -0,0 +1,204 @@ +OFF +192 10 0 +57.531272273 -38.894738065 -35.596646778 +57.542283368 -38.844672176 -35.872878527 +57.525259607 -38.457749173 -36.063844298 +57.309433067 -35.185838007 -36.31068148 +57.278886643 -34.784009496 -36.264087737 +57.223961763 -34.229772196 -35.956319563 +57.213142302 -34.1271718 -35.88693934 +57.197355531 -33.980950024 -35.781069563 +56.835054126 -33.518038801 -29.500936982 +56.822186495 -33.5023233 -29.276923905 +56.782262006 -33.52500907 -28.486779477 +56.772038172 -33.537489246 -28.275560785 +56.74007394 -33.700228795 -27.45052095 +56.74883641 -33.868830364 -27.392897338 +56.760741645 -34.097490701 -27.315154974 +56.775635836 -34.38025532 -27.222291796 +56.86101069 -35.599486435 -27.224536151 +56.974032333 -37.160980714 -27.297464138 +57.003835374 -37.559711778 -27.334030629 +57.008376036 -37.601628591 -27.364667914 +57.022042641 -37.664297958 -27.54139207 +57.10159686 -38.011201507 -28.593939257 +57.117882487 -38.077558339 -28.815607442 +57.490167508 -38.845650839 -34.879568422 +42.253287429 -39.865616399 -31.237740888 +42.806859459 -39.862105064 -35.452286882 +55.963165304 -38.015477551 -35.586781968 +56.985742173 -37.871604326 -35.577737756 +57.738751973 -37.756941856 -35.076572432 +57.428147075 -37.701406838 -29.449414785 +57.10765397 -37.717459648 -27.804766993 +57.043844053 -37.724096157 -27.672501577 +56.886459473 -37.742399843 -27.456051834 +56.745254072 -37.76068526 -27.367565821 +54.434557148 -38.077610247 -26.923788537 +53.62273993 -38.192259119 -26.955297862 +51.519007624 -38.490283284 -27.089405984 +51.041035593 -38.558734221 -27.161816326 +43.652535913 -39.622649519 -28.610160152 +42.962518738 -39.723852122 -28.849968836 +42.822882989 -39.747250381 -29.064061915 +47.000499188 -35.234184742 -29.040005574 +45.895175246 -35.268729967 -29.043512226 +43.587628554 -35.544352585 -29.043779406 +42.800055626 -35.658244342 -29.043183594 +42.378480026 -35.922894586 -29.03580482 +42.285497234 -36.056257892 -29.031578098 +42.292757421 -37.1193097 -28.994701319 +42.316216892 -37.672691045 -28.97542102 +42.609786853 -39.623153218 -28.906567708 +42.614482601 -39.649419494 -28.905637322 +42.924698978 -39.748732042 -28.900874892 +47.896795672 -39.244873792 -28.897178752 +48.926042655 -39.115852504 -28.897270452 +49.450279791 -39.039096965 -28.897699802 +49.854899943 -38.905160008 -28.90062015 +49.882777712 -38.855018495 -28.902239437 +49.981469988 -38.653269337 -28.908812147 +49.980088857 -38.502483414 -28.914044336 +49.947923596 -38.052603825 -28.929774265 +49.940673002 -37.952070039 -28.93328967 +49.89992045 -37.719303268 -28.941530911 +49.825008126 -37.38654781 -28.953383183 +49.77949503 -37.201398751 -28.959994231 +49.727861971 -37.113947313 -28.963245078 +47.848756981 -35.32002063 -29.03342047 +54.265306757 -34.103364498 -27.113141535 +53.721774897 -34.125133725 -27.11470015 +52.413377462 -34.290611196 -27.114532863 +52.15333392 -34.346475909 -27.113703251 +51.93331568 -34.578144065 -27.10660987 +49.926663344 -36.877441888 -27.035454967 +49.874111701 -36.980011218 -27.032123514 +49.897113929 -37.369631221 -27.018521207 +49.93186478 -37.761344318 -27.004796353 +49.973492985 -38.134909449 -26.991671248 +50.087458109 -38.674522576 -26.972482991 +50.14565235 -38.813605533 -26.967414648 +50.176350715 -38.842887341 -26.966269081 +50.250349934 -38.879800929 -26.964674715 +50.707150327 -38.87594795 -26.962864223 +52.74603026 -38.547842016 -26.965559524 +54.687001875 -38.135281849 -26.971598725 +54.78696727 -37.993390618 -26.976091312 +54.835992246 -37.868400281 -26.980214898 +54.735796783 -36.241060289 -27.037045684 +54.608228321 -34.785247097 -27.088047764 +54.515437673 -34.284584947 -27.105795848 +54.474854136 -34.11546577 -27.111830313 +55.923822759 -33.664281314 -28.322139157 +55.722586035 -33.667770077 -28.322874652 +55.492954851 -33.689049159 -28.323114367 +54.86419354 -33.767457977 -28.323072544 +54.819295053 -33.775362284 -28.322989655 +54.71102404 -33.807792156 -28.322326396 +54.611777017 -33.932343977 -28.318431744 +54.583243756 -33.984974951 -28.31672896 +54.694458689 -36.580456214 -28.226295041 +54.795985989 -37.08864217 -28.208248997 +55.581340015 -38.212524896 -28.1659524 +55.593730692 -38.227459862 -28.165382015 +56.487247173 -38.171368135 -28.163523579 +57.386880343 -36.191007863 -28.228335175 +57.361119523 -35.463080613 -28.253675112 +57.007486583 -34.89396626 -28.274905866 +56.204379523 -33.727971076 -28.318737654 +56.186585668 -33.707464744 -28.31952414 +56.025936658 -33.67549225 -28.321316007 +47.673527497 -37.258152339 -28.943716842 +48.460379254 -37.218450814 -32.965096698 +48.631076073 -37.209601384 -33.824050677 +49.409802969 -37.099558218 -33.789997706 +51.997764733 -36.729433519 -33.426320666 +52.039742638 -36.723041799 -33.398402043 +52.067048183 -36.711870392 -32.982334272 +52.107962588 -36.691314729 -32.142381352 +52.135326441 -36.621565734 -28.403530209 +52.137858496 -36.609575931 -27.743508288 +52.122377578 -36.605190204 -27.371262616 +51.956172049 -36.624223033 -27.12584749 +51.886345547 -36.632422985 -27.034308431 +51.701268643 -36.657542773 -26.983755649 +50.4121345 -36.836863717 -26.878514502 +50.277447215 -36.856978968 -26.945809772 +41.877465015 -35.851440127 -30.592808864 +41.923677909 -35.908076721 -34.17440555 +41.940406964 -35.907431467 -34.271183189 +42.025604039 -35.903782326 -34.743453769 +42.062310135 -35.899744698 -34.80705518 +43.512668819 -35.706079983 -35.384018491 +53.159859484 -34.361532156 -36.023756048 +53.277170459 -34.345067363 -36.025014927 +57.644071036 -33.72902896 -35.893931785 +57.648678984 -33.721155009 -35.483963678 +56.931660035 -33.68463196 -27.694971754 +56.8486508 -33.690424494 -27.361745204 +56.508200107 -33.73702152 -27.290818417 +54.42017874 -34.023895846 -26.917635946 +52.064163854 -34.354728026 -26.901517227 +42.524994666 -35.727148928 -28.704365814 +42.455746646 -35.738491034 -28.795701139 +42.229805701 -35.776814747 -29.168420893 +46.876721268 -33.239537256 -35.621461937 +46.492795466 -33.247957592 -35.622803985 +40.653703301 -33.469130718 -35.63998786 +40.020108346 -33.507231688 -35.641363697 +39.812041902 -33.520394431 -35.641792953 +39.682888847 -33.650876864 -35.637820016 +39.702423524 -33.986843814 -35.626092107 +39.901546086 -35.379963464 -35.576958497 +40.203231484 -37.37603646 -35.506489754 +40.435606938 -38.909783567 -35.452340414 +40.721729784 -40.792734814 -35.385858755 +40.729242519 -40.824732829 -35.384717716 +40.827788938 -40.94321962 -35.380191517 +41.119563663 -40.941591443 -35.379006224 +43.047060946 -40.708410522 -35.378885398 +49.627807131 -34.883451456 -35.552775097 +49.662974769 -34.068063074 -35.580887181 +49.416058321 -33.896831182 -35.58787298 +49.072521599 -33.69196466 -35.596435764 +48.780684313 -33.549379856 -35.602619814 +47.257799282 -33.287669019 -35.618171887 +50.747147014 -34.301446963 -33.621374373 +48.39332418 -34.496065983 -33.624646117 +47.796061756 -35.32506094 -33.59845457 +48.534725225 -37.190845964 -33.530641992 +49.496062846 -37.189099561 -33.52661129 +51.296538024 -36.918693268 -33.52832129 +52.031681164 -36.755359665 -33.530853909 +52.061689351 -36.650183637 -33.534371652 +52.118608023 -36.29753705 -33.546352318 +52.146930592 -34.787363034 -33.598575133 +52.035091708 -34.587787497 -33.605968476 +50.802981154 -34.309398356 -33.620861157 +56.539844906 -33.010313866 -36.129063109 +50.319876907 -33.392999639 -36.184965116 +45.88724082 -33.711979158 -36.175316545 +43.95672484 -34.126644218 -35.876137504 +43.856398211 -34.204652087 -35.80019298 +43.79684445 -34.255366314 -35.750396006 +43.186684534 -35.071025864 -34.923481727 +43.245222997 -35.826956259 -34.110441344 +43.39505417 -36.000206058 -33.913898179 +44.285809078 -36.089397364 -33.751852585 +48.35754716 -35.77235409 -33.786426698 +57.607003782 -34.230814444 -34.743596259 +57.977757991 -33.859025306 -35.113585953 +57.976231145 -33.84942716 -35.123967847 +57.828904198 -33.275580509 -35.748864758 +57.751802126 -33.002660651 -36.046590138 +57.706962082 -32.976358416 -36.078081368 +24 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 +17 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 +25 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 +23 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 +19 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 +16 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 +18 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 +21 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 +12 163 164 165 166 167 168 169 170 171 172 173 174 +17 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-15-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-15-polygons.off new file mode 100644 index 00000000000..ceaeaaf9a6c --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-15-polygons.off @@ -0,0 +1,77 @@ +OFF +60 15 0 +60.449881891 -13.692214483 -35.548420038 +60.455828185 -25.202689488 -35.743109903 +51.889312672 -25.202689488 -36.004751788 +51.883366377 -13.692214483 -35.810061923 +56.013494661 -22.286077626 -35.794136224 +58.289635919 -22.325795715 -35.794829611 +58.289635919 -22.50061645 -25.78088178 +56.013494661 -22.460898362 -25.780188393 +58.070892334 -21.905636832 -26.101082072 +58.070892334 -21.746641653 -35.20990978 +60.258117676 -21.746641653 -35.20990978 +60.258117676 -21.905636832 -26.101082072 +54.42440687 -22.038030512 -35.922176361 +54.5656494 -13.946251373 -35.922176361 +54.5656494 -13.946251373 -26.198154449 +54.42440687 -22.038030512 -26.198154449 +54.363766926 -21.719850201 -35.365935422 +56.286979614 -21.753409775 -35.366521296 +56.286979614 -21.912655257 -26.244743216 +54.363766926 -21.879095683 -26.244157342 +60.129200355 -20.359792807 -33.698807129 +60.084094816 -23.886993185 -27.588442933 +59.959713735 -19.368804043 -24.981241847 +60.004819274 -15.841603666 -31.091606043 +54.23652352 -17.103515563 -26.393317799 +60.056166552 -17.100143515 -26.273959576 +60.056166552 -22.551184854 -26.119959504 +54.23652352 -22.554556902 -26.239317727 +61.530666604 -12.199937334 -35.495003395 +61.531466955 -19.059906537 -35.545595555 +58.888261444 -19.059906537 -35.587410171 +58.887461093 -12.199937334 -35.536818011 +60.840349073 -16.766832339 -30.09282598 +58.391720941 -17.199597832 -30.266048756 +57.771486126 -13.698842248 -30.244583924 +60.220114259 -13.266076754 -30.071361148 +60.28580042 -17.233539007 -27.986459964 +55.030055 -18.643526755 -28.248937225 +54.6463142 -17.207471362 -28.279326743 +59.90205962 -15.797483614 -28.016849482 +54.840260431 -13.995359805 -35.871916394 +58.620622307 -14.078480263 -35.54503007 +58.010141023 -14.433155993 -28.575147284 +54.229779147 -14.350035535 -28.902033608 +58.291708667 -16.784192496 -30.1751564 +54.730118484 -17.412277855 -30.279859285 +54.229931677 -14.58528037 -30.223846608 +57.79152186 -13.95719501 -30.119143724 +54.276560845 -14.161177028 -35.658184052 +56.497525215 -13.769561087 -35.658184052 +56.497525215 -13.769561087 -30.807325363 +54.276560845 -14.161177028 -30.807325363 +53.832898877 -17.601506764 -29.896430592 +54.485161788 -17.323940082 -27.303531189 +58.745918537 -16.480552413 -28.465639489 +58.093655627 -16.758119095 -31.058538892 +56.32506092 -17.944488816 -30.541171077 +56.552264209 -17.928601214 -26.195287696 +56.675291733 -19.687976768 -26.195287696 +56.448088443 -19.703864369 -30.541171077 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 +4 16 17 18 19 +4 20 21 22 23 +4 24 25 26 27 +4 28 29 30 31 +4 32 33 34 35 +4 36 37 38 39 +4 40 41 42 43 +4 44 45 46 47 +4 48 49 50 51 +4 52 53 54 55 +4 56 57 58 59 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-20-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-20-polygons.off new file mode 100644 index 00000000000..bc5449729ba --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-20-polygons.off @@ -0,0 +1,364 @@ +OFF +342 20 0 +55.950882754 -37.928082671 -35.581798553 +42.794903635 -39.777034958 -35.45759964 +42.251569898 -39.853395535 -31.244499207 +42.826445923 -39.772601979 -29.065000534 +42.966601764 -39.75290436 -28.851200104 +43.6572015 -39.655846896 -28.613300323 +51.049219606 -38.616966502 -27.15929985 +51.527367542 -38.549767192 -27.087600708 +53.631425634 -38.254061111 -26.961799622 +54.443319396 -38.139956884 -26.928699493 +54.598729575 -38.118115408 -26.958000183 +56.752938263 -37.815361121 -27.371799469 +56.893928708 -37.795546206 -27.456899643 +57.050787471 -37.773501144 -27.673999786 +57.114276079 -37.764578403 -27.805400848 +57.430773881 -37.720097537 -29.454500198 +57.727708863 -37.678366047 -35.071098328 +56.973481595 -37.784365777 -35.571998596 +57.128820972 -32.859865572 -35.906313471 +56.092315122 -32.892757908 -35.905423667 +53.531802824 -32.987599673 -35.902988434 +53.131890005 -33.003318504 -35.902592276 +52.819892251 -33.019272131 -35.902218802 +52.437676335 -33.04156052 -35.90171338 +51.104816846 -33.119385678 -35.899949111 +50.631366206 -33.182880448 -35.898696746 +50.103776353 -33.534752172 -35.892395016 +49.973149294 -33.864405921 -35.886601972 +57.482314445 -38.834862269 -35.802143086 +57.69151585 -38.865082743 -35.801679396 +57.837295652 -38.853311529 -35.801929241 +58.559815723 -38.773554864 -35.80354129 +58.704485889 -38.703309098 -35.804811319 +58.708489114 -38.535816637 -35.807735685 +57.787589473 -33.050587428 -35.903185598 +57.745416344 -32.910132062 -35.905624035 +57.358696184 -32.878205408 -35.906063424 +57.549169901 -38.891850328 -35.595699785 +57.55940112 -38.842665597 -35.871975904 +57.536271527 -38.46325276 -36.063291575 +57.263485222 -35.19506617 -36.313120119 +57.226027082 -34.794714242 -36.266893573 +57.160783644 -34.23373546 -35.959636804 +57.148060442 -34.129970819 -35.89035126 +57.129676171 -33.983417599 -35.784615835 +57.011143085 -33.650359576 -34.085362143 +57.013319039 -33.900879099 -33.710102186 +57.192708085 -37.129491008 -31.750743202 +57.258400756 -37.774804486 -31.926288052 +57.341129536 -38.143731871 -32.885302769 +57.507379014 -38.845338077 -34.878667866 +57.522193082 -38.863107997 -35.130709564 +57.264980486 -38.214204621 -31.320623138 +57.288425206 -37.948030345 -32.208928703 +57.287080503 -37.823286617 -32.390820517 +57.196480988 -36.453127805 -32.947273272 +57.02663775 -34.066527894 -33.687792241 +57.001642392 -33.761342931 -33.720199243 +56.746145765 -33.510388201 -29.280930061 +56.706377891 -33.530972625 -28.490768809 +56.696329231 -33.543130521 -28.279539639 +56.667237863 -33.706808808 -27.454353562 +56.678920134 -33.875080094 -27.396576038 +56.694961153 -34.105303251 -27.318624013 +56.71459904 -34.385759797 -27.225503494 +56.821085171 -35.60222239 -27.226633438 +56.95737403 -37.158665107 -27.228872001 +56.989584173 -37.490400298 -27.289453592 +56.998025406 -37.559896345 -27.334334948 +57.003277529 -37.601528877 -27.364933891 +57.018006121 -37.663645853 -27.54160029 +57.121448083 -38.080023244 -28.815431281 +57.133951738 -38.095045529 -29.028124843 +47.002115986 -35.239691152 -29.008054086 +45.896392951 -35.27264826 -29.007142065 +43.586753084 -35.540267622 -29.001767871 +42.799260438 -35.65443187 -28.999535534 +42.377440867 -35.91821076 -28.994803458 +42.284869891 -36.053162284 -28.992420029 +42.292381154 -37.117501978 -28.973847028 +42.315879554 -37.671209237 -28.964190662 +42.610114998 -39.624830755 -28.930184899 +42.614814845 -39.651121295 -28.929727498 +42.924370649 -39.748000151 -28.928131029 +47.896036652 -39.242777696 -28.93846291 +48.925127866 -39.113214823 -28.941037589 +49.449108697 -39.035512361 -28.942553306 +49.854457666 -38.904316063 -28.944966479 +49.882143572 -38.853437131 -28.945862873 +49.979988182 -38.648434262 -28.949470473 +49.978698001 -38.497943048 -28.952096514 +49.939299924 -37.94741726 -28.961692512 +49.898070522 -37.712773801 -28.965775045 +49.823707065 -37.381975918 -28.971525611 +49.778530145 -37.198031854 -28.974722115 +49.727364842 -37.112312494 -28.976202537 +47.849130712 -35.320937413 -29.006894172 +54.26455998 -34.099825659 -27.074383193 +53.721493205 -34.123310125 -27.073807897 +52.412665605 -34.287106944 -27.070550536 +52.152666502 -34.34313511 -27.069493506 +51.932559307 -34.574523192 -27.065388175 +49.926489914 -36.876585559 -27.024600532 +49.873889152 -36.978997973 -27.022797165 +49.896991927 -37.369123881 -27.015995567 +49.932436726 -37.763582944 -27.009122105 +49.974567419 -38.139166608 -27.0025801 +50.087817155 -38.676263527 -26.993240966 +50.146446877 -38.817038623 -26.990801963 +50.177147531 -38.846341036 -26.990299918 +50.251144609 -38.883264635 -26.989678054 +50.709017518 -38.883494849 -26.989813519 +52.746738903 -38.55108662 -26.9962356 +53.246180841 -38.443949259 -26.998257551 +54.68645476 -38.133822136 -27.00410877 +54.787314654 -37.995268154 -27.006557596 +54.83620694 -37.86974145 -27.008763233 +54.735802015 -36.241082096 -27.037156671 +54.607993255 -34.783885789 -27.062549319 +54.514765965 -34.281408482 -27.071290357 +54.473949263 -34.11135221 -27.074245814 +55.923165863 -33.66107997 -28.283291704 +55.721970278 -33.664707966 -28.283167096 +55.492263419 -33.685688925 -28.282730951 +54.863461713 -33.763917137 -28.281174127 +54.818562711 -33.771818225 -28.281022556 +54.710261414 -33.804135058 -28.280425558 +54.611704769 -33.93132252 -28.278175807 +54.583101055 -33.983702159 -28.277252942 +54.694607482 -36.581122961 -28.231955667 +54.796423144 -37.09056789 -28.223095644 +55.581930246 -38.215454284 -28.203702961 +55.594434708 -38.230824294 -28.203438526 +56.488686116 -38.177562648 -28.204640488 +57.387112538 -36.192092922 -28.239565403 +57.360885648 -35.462172467 -28.252296282 +57.005468788 -34.886116803 -28.262241568 +56.203446905 -33.723773843 -28.282282928 +56.185970204 -33.704455788 -28.28261475 +56.025265067 -33.672247719 -28.283127902 +54.684527406 -33.405158995 -35.980499268 +52.840355313 -33.66434048 -35.914600372 +50.298316373 -34.021600755 -35.712200165 +50.146575643 -34.042926524 -35.076698303 +50.370312712 -34.011482329 -34.942100525 +51.262307794 -33.886120596 -34.847198486 +52.830671248 -33.665701487 -34.76720047 +53.840559009 -33.523771018 -34.772800446 +54.863497296 -33.380006417 -34.784301758 +56.736435872 -33.116782066 -34.813899994 +57.426618099 -33.01978328 -34.91519928 +57.500343966 -33.009421785 -35.022499084 +57.700497213 -32.981292081 -35.795200348 +57.555580771 -33.001658759 -35.905601501 +57.354935111 -33.029857667 -35.915100098 +48.621807078 -37.143649056 -33.825000763 +48.453196895 -37.167345672 -32.962799072 +47.676114177 -37.276557526 -28.9416008 +50.284887362 -36.909918365 -26.945100784 +50.419738126 -36.890966326 -26.876800537 +51.708616609 -36.709826268 -26.983400345 +51.893570707 -36.683832665 -27.034000397 +51.963174835 -36.674050443 -27.123699188 +52.128784183 -36.650775567 -27.368600845 +52.143360813 -36.648726955 -27.742700577 +52.139225384 -36.649308152 -28.404499054 +52.102778831 -36.654430381 -32.141799927 +52.059823949 -36.660467296 -32.981399536 +52.031507661 -36.66444689 -33.396701813 +51.989461934 -36.670356032 -33.424999237 +49.400616698 -37.034194502 -33.790901184 +54.847522127 -37.880426744 -27.399305551 +54.85031915 -37.867861825 -27.473368671 +54.852811172 -37.356894894 -28.370492016 +54.650619323 -35.05622795 -28.353202364 +54.57671536 -34.256962345 -28.277600067 +54.569426129 -34.202223857 -28.230074308 +54.546248122 -34.045962873 -28.049361343 +54.515949058 -33.996877595 -27.55505107 +54.489578231 -34.055981064 -26.955489613 +54.49483039 -34.127315902 -26.936693406 +54.698040786 -36.803295332 -26.349187954 +54.716661484 -36.992775423 -26.388028794 +54.810810057 -37.682582026 -27.030485 +54.825884175 -37.79117579 -27.136427008 +54.837217706 -37.849216246 -27.255337687 +52.270104944 -36.663452907 -31.464909093 +52.288022124 -36.647458038 -31.832088264 +52.290647983 -35.833925923 -33.234930813 +52.278240147 -35.621162718 -33.35290785 +52.25634166 -35.347465261 -33.391817125 +52.207511364 -34.885963856 -33.231116094 +52.129996107 -34.513199939 -32.377583041 +51.932532886 -34.298351798 -28.981397062 +51.926823013 -34.307349379 -28.857897536 +51.878144637 -34.474756851 -27.654189546 +51.875272659 -34.499319078 -27.558749733 +51.865033235 -34.723745628 -26.990885148 +51.86987027 -34.857496907 -26.860397573 +51.945569366 -35.741117834 -26.829837227 +52.021187622 -36.559065746 -26.906956455 +52.021717251 -36.562402006 -26.911475626 +52.029800786 -36.598189883 -27.005615396 +52.159895054 -36.65660194 -29.381374784 +53.272587686 -34.312459236 -36.021499634 +53.155279768 -34.328945789 -36.020301819 +48.236363368 -35.020254406 -35.69549942 +43.509643203 -35.684551603 -35.380001068 +42.060686121 -35.888189241 -34.805400848 +42.024134531 -35.893326232 -34.742099762 +41.940084731 -35.905138661 -34.275398254 +41.923590776 -35.907456735 -34.177600861 +41.886078567 -35.912728732 -30.591600418 +42.241879483 -35.862724175 -29.165800095 +42.468725868 -35.830842994 -28.797199249 +42.538195766 -35.821079637 -28.70359993 +52.08174457 -34.479821322 -26.901399612 +54.437720299 -34.148710526 -26.915300369 +56.524835103 -33.85538567 -27.285400391 +56.865113496 -33.80756266 -27.357700348 +56.947313231 -33.796010241 -27.690200806 +57.20307568 -33.760065173 -34.630599976 +56.745283131 -33.82440372 -35.604698181 +56.551115716 -33.85169217 -35.701999664 +56.307211646 -33.885970652 -35.776199341 +54.048506984 -34.107919643 -26.88419453 +53.435539667 -34.142989269 -26.883395751 +53.148640165 -34.23628539 -26.88168011 +53.107026406 -34.279697629 -26.880909785 +52.014043437 -35.423708842 -26.860611078 +52.017528895 -35.449648107 -26.860159437 +52.106516786 -35.695864315 -26.85588948 +54.055891262 -36.763616145 -26.837848485 +54.149787907 -36.760537486 -26.837930819 +54.644929079 -36.178907179 -26.848232504 +54.808367061 -35.839739525 -26.854201584 +54.849399206 -35.600721058 -26.858385531 +54.789216537 -35.349243484 -26.862756086 +54.446620706 -34.14542041 -26.88366133 +54.405826667 -34.124166437 -26.884019836 +46.877026038 -33.240243725 -35.597618036 +46.493664215 -33.250761605 -35.597317689 +44.860252214 -33.308532609 -35.595811855 +41.160443187 -33.445529225 -35.59229385 +40.652964208 -33.46544531 -35.591791672 +40.019685171 -33.504696429 -35.590913728 +39.811689952 -33.518114411 -35.59061619 +39.682486106 -33.648436055 -35.588302404 +39.702088904 -33.98476913 -35.582438554 +39.901609464 -35.379852771 -35.558151768 +40.203300265 -37.376610473 -35.523395446 +40.436121799 -38.912550764 -35.496660516 +40.722424925 -40.796808858 -35.463862896 +40.730029792 -40.829165284 -35.463300515 +40.828524958 -40.947505018 -35.461265207 +41.120434212 -40.946408526 -35.461373268 +43.047611811 -40.712110551 -35.466049413 +49.627900582 -34.884120151 -35.569766443 +49.663215579 -34.069029687 -35.584002491 +49.417067517 -33.900620528 -35.586866651 +49.073356938 -33.695003503 -35.590350458 +48.78145292 -33.552096599 -35.592755604 +47.258020227 -33.288107003 -35.59689877 +45.874309551 -34.103482743 -36.284841027 +45.50593772 -34.18070125 -36.167047034 +45.28352959 -34.266823595 -36.030197208 +43.891696914 -34.918597898 -34.986054548 +43.40947237 -35.243231059 -34.459863066 +43.25024795 -35.514035983 -34.013861413 +43.283364397 -35.562341827 -33.932517342 +43.297995817 -35.576325205 -33.908823657 +48.071461161 -35.886309982 -33.254352373 +48.093970501 -35.887215932 -33.252191049 +48.293644006 -35.882679074 -33.253940845 +48.359288153 -35.862993936 -33.284790747 +49.646109547 -35.411392954 -33.99888992 +49.674696536 -35.399374122 -34.018059241 +49.707414035 -35.334335857 -34.125334303 +49.688880312 -34.594244518 -35.357403861 +49.387565521 -34.367885533 -35.742822992 +49.336677794 -34.338091606 -35.79387893 +47.746391014 -34.224585655 -36.028946749 +50.746568926 -34.298844377 -33.598728875 +48.39437748 -34.499479894 -33.594510747 +47.796427895 -35.326097404 -33.579902127 +48.535766514 -37.195088885 -33.547508955 +49.496845728 -37.192448701 -33.547847809 +51.295096998 -36.91371966 -33.553260108 +52.031481191 -36.75507757 -33.556253121 +52.061263151 -36.649017069 -33.558113205 +52.118163609 -36.296193756 -33.564288154 +52.146148257 -34.784264198 -33.590683488 +52.035426114 -34.588827823 -33.594060594 +50.802580422 -34.307472062 -33.598595364 +42.577020952 -39.712280814 -29.994361271 +42.645009404 -39.677842411 -31.34399374 +42.644146754 -39.512930198 -31.601850093 +42.614794924 -38.996867633 -31.902142899 +42.449592898 -37.070307491 -31.96582423 +42.358460978 -36.209902453 -31.664420589 +42.347386369 -36.118674119 -31.605624105 +42.286667964 -35.940886966 -30.747122127 +42.212877334 -35.787845942 -29.598982847 +42.204807741 -35.798259404 -29.428273862 +42.175471418 -35.854647203 -28.776858931 +42.261131036 -36.819055257 -28.801281978 +42.508925649 -39.593889466 -28.896858298 +42.517963046 -39.674388985 -28.934772742 +50.479128095 -34.489653521 -36.117099762 +49.559203245 -34.618940527 -36.019298553 +49.215978733 -34.667177586 -35.766998291 +51.823892678 -34.300659183 -33.381500244 +52.32782742 -34.229835774 -32.95059967 +56.618600397 -33.626806959 -32.68119812 +56.704400354 -33.614748561 -32.768501282 +57.158519766 -33.55092624 -35.709899902 +57.104038137 -33.558583133 -35.803699493 +56.844790113 -33.595018067 -35.915100098 +45.201472802 -37.420135825 -29.443658898 +44.977567342 -37.534059397 -29.441602449 +44.895485249 -37.836337344 -29.436301966 +44.780444694 -39.492700935 -29.407359391 +47.689734032 -39.315811642 -29.4113328 +47.756801393 -38.706010298 -29.421995732 +47.62025001 -38.377997535 -29.427678746 +46.721910546 -37.761351532 -29.438167039 +46.401313699 -37.657333053 -29.439884747 +50.027475079 -38.881402168 -27.196314018 +50.04901985 -38.847262143 -27.6626243 +50.052157219 -38.837699445 -27.738164125 +50.076362793 -38.753314375 -28.338611382 +50.083638819 -38.586046034 -28.755090297 +49.971326334 -37.240820381 -28.857346856 +49.937385717 -36.925713151 -28.736218688 +49.872856653 -36.881041196 -27.583907055 +49.842798308 -36.884004765 -27.007613678 +49.844252387 -36.952592731 -26.921189687 +49.898274547 -37.576538401 -26.910430627 +49.912719925 -37.73481283 -26.921800765 +49.94587104 -38.088289863 -26.964111497 +49.986832834 -38.50125305 -27.055964437 +50.012154863 -38.738710185 -27.142400422 +18 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +19 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +15 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 +21 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 +24 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 +24 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 +19 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 +15 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 +16 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 +15 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 +18 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 +21 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 +15 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 +23 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 +19 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 +12 282 283 284 285 286 287 288 289 290 291 292 293 +14 294 295 296 297 298 299 300 301 302 303 304 305 306 307 +10 308 309 310 311 312 313 314 315 316 317 +9 318 319 320 321 322 323 324 325 326 +15 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-40-polygons.ply b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-40-polygons.ply new file mode 100644 index 00000000000..a6e2c170d34 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/real-data-test/test-40-polygons.ply @@ -0,0 +1,437 @@ +ply +format ascii 1.0 +element vertex 384 +property double x +property double y +property double z +element face 40 +property list uchar int vertex_indices +property uchar red +property uchar green +property uchar blue +property uchar alpha +end_header +03.29868532018736 393.5299726324156 21.80889597269399971 +30.43944002094213 393.5381471058354 23.139587462290656106 +30.44661123899277 417.4042486362159 22.993328973862105613 +03.305856538238 417.3960741627961 21.662637484265449217 +11.95831769844517 396.2328201103956 28.294205721002068543 +11.66516924533062 396.60181907285 27.354071180336173796 +10.76777932967525 398.8796317894012 26.740174206905063414 +08.42645351670217 405.7806099280715 27.027606581919823014 +08.28849473420996 406.6192669896409 27.896408416272603148 +08.30528880935162 407.0143724363297 28.771011472796086395 +08.78512516152114 406.7632776526734 31.005693720187988305 +09.66730323340744 405.4849680690095 33.503852504771195697 +10.36672410042956 403.4724039435387 33.514516960131004453 +11.97644138394389 398.8209823416546 33.500601977983016866 +12.04349625611212 396.3510358324274 29.01188164949416759 +31.64162581833079 400.4716062713414 26.308578369288170506 +31.49925644847099 400.8870130516589 24.812041777679500143 +31.20062054879963 401.7728082975373 24.432037617953483277 +29.51961759175174 406.768534982577 24.136002432398530715 +26.2994834567653 416.3442336115986 24.691150469599055128 +26.12519626447465 416.8626198163256 24.742064757566822664 +26.11351498460863 416.9352899761871 31.996124021056861153 +26.14477371040266 416.84700401593 32.883146439811760331 +26.29246082087047 416.4139445247129 34.027120597282646486 +26.48416705231648 415.8475459283218 34.69710175926366702 +27.16982886847109 413.8172330595553 36.23002493464264262 +30.71549923007842 403.27671257779 36.235069503100930888 +31.51127581414767 400.8956648781896 33.29705406037010107 +09.96794394159224 393.5845419801772 25.462325656801109375 +09.59196252713446 394.2652920279652 23.067847779602740133 +08.92245784553234 396.0885722236708 22.294101987077734606 +06.58075666427612 402.9881431758404 22.571126564842412421 +06.33355139067862 403.7206296017393 22.623916850192472339 +05.15569547971245 407.2313878554851 22.993608996053804816 +05.25199429236818 407.1149218408391 23.937538957325156019 +05.54563176503871 406.5454468391836 25.591618494727295996 +09.17227164178621 396.1855942578986 27.022489921495431275 +09.30650311848149 395.7963385824114 27.042265768744979226 +05.29625984642189 407.2173816617578 21.984000000000001762 +09.19340264739003 395.4237939463928 21.984000000000001762 +09.19340264739003 395.4237939463928 37.783000000000001251 +05.29625984642189 407.2173816617578 37.783000000000001251 +26.92756963765714 414.7398494333029 21.984000000000001762 +30.84900872863363 402.8770360965282 21.984000000000001762 +30.84900872863363 402.8770360965282 37.783000000000001251 +26.92756963765714 414.7398494333029 37.783000000000001251 +12.30659139517229 394.2659373255447 21.984000000000001762 +16.94558888243046 395.7719450648874 21.984000000000001762 +16.94558888243046 395.7719450648874 37.783000000000001251 +12.30659139517229 394.2659373255447 37.783000000000001251 +07.65509033796843 410.8346233814955 21.984000000000001762 +23.74691606254783 416.1841798843816 21.984000000000001762 +23.74691606254783 416.1841798843816 37.783000000000001251 +07.65509033796843 410.8346233814955 37.783000000000001251 +25.3789191886317 398.2966175414622 21.984000000000001762 +29.0789147822652 399.4067870927975 21.984000000000001762 +29.0789147822652 399.4067870927975 37.783000000000001251 +25.3789191886317 398.2966175414622 37.783000000000001251 +24.69913416169584 398.4604729581624 21.984000000000001762 +23.12052289722487 394.1485271891579 21.984000000000001762 +23.12052289722487 394.1485271891579 37.783000000000001251 +24.69913416169584 398.4604729581624 37.783000000000001251 +18.10733771696687 396.8055807435885 21.984000000000001762 +21.71259050397202 393.9449482774362 21.984000000000001762 +21.71259050397202 393.9449482774362 37.783000000000001251 +18.10733771696687 396.8055807435885 37.783000000000001251 +04.78117047424894 409.3697847705334 21.984000000000001762 +07.15099212841596 410.804912161082 21.984000000000001762 +07.15099212841596 410.804912161082 37.783000000000001251 +04.78117047424894 409.3697847705334 37.783000000000001251 +29.41121161729097 399.4289674684405 21.984000000000001762 +31.64206198463216 400.8534375298768 21.984000000000001762 +31.64206198463216 400.8534375298768 37.783000000000001251 +29.41121161729097 399.4289674684405 37.783000000000001251 +12.03708795062266 396.1833529956639 27.527064983727544956 +11.87521254806779 396.6743886657059 27.320104436654222724 +11.10706354642753 398.9980785492808 26.669613906293310635 +09.34694079356268 404.2894131932408 26.888329679975871755 +08.80703900079243 405.9123338526115 26.963083993558033313 +08.53773760295007 406.7052164496854 27.858198002959401407 +08.41652493539732 407.0524781392887 28.757203074732391457 +08.52758264017757 406.6738497940823 31.053074612094864193 +08.87626182776876 405.6203993018717 31.280143404408594421 +10.76737655617762 399.9344173343852 31.089279419526068438 +11.45857777469791 397.866535901092 30.485932862964549628 +11.71811043436173 397.0950137358159 30.005155312608625451 +11.97905500605702 396.329041252844 29.018845753107601837 +12.00984423828777 396.2506101094186 28.286031205214388962 +20.80346840480343 394.5582724893466 26.252471478292136453 +20.83452274359297 394.8729069987312 26.251258579730347265 +21.21817035262939 396.8859696928412 26.252499568428902421 +21.90245209762361 397.704919565469 26.27871021963073872 +23.85032996872906 398.3787633813918 26.367671578067529481 +23.96741564373951 398.021926051937 26.376459282197174616 +23.94998104381375 396.9036475494504 26.385293174258549698 +23.86145736963954 395.9195628045127 26.389505548962915782 +23.64098852674942 395.0058241290972 26.386687586549669504 +23.41368229675572 394.7338786125183 26.37798005106014898 +22.96944047545549 394.2039216337726 26.360949034067743924 +21.23965976189356 393.663882621564 26.281443101899640169 +20.93250534043182 393.7542659183964 26.265712519874796271 +20.80562129733153 394.2402452873066 26.255329819316102657 +31.64227601420134 400.4718440799043 26.308601208285377737 +31.50001746148337 400.8872672170401 24.812038144656522576 +31.20135234494228 401.7730528181419 24.43203426939589562 +29.52001882740296 406.7686698706821 24.136001628475238334 +26.29915334878024 416.3441157452762 24.69114248169261927 +26.1248234231025 416.8624914428219 24.742061702833776593 +26.11248733312823 416.9349386068061 31.996118691243278676 +26.14367313263938 416.8466270966455 32.883139959273187003 +26.2912882338278 416.4135445440188 34.027115702246646833 +27.16864283324685 413.8168328749016 36.230025488649516774 +30.71506579651032 403.276563603431 36.235066279730283156 +31.51127557805739 400.8956623580307 33.297050994041001104 +09.59564814821351 394.266237183474 23.070070483572628461 +08.98182004480623 396.1089351205155 22.289983680547717171 +06.67405171331484 403.0197057845071 22.568072978725464139 +06.42911847715732 403.7530555464327 22.620053542422731141 +05.25583994959015 407.2653012191877 22.990070824541810168 +05.29908964328934 407.1307168509811 23.937067712976382694 +05.49721778184175 406.5284369569272 25.598103495304709298 +05.84691255330108 405.4806289412081 25.672971400915226781 +06.42916319612414 403.7363835535944 25.72598606830432999 +08.9856130204862 396.0788739966229 25.802009978416201363 +09.36904216720723 394.9336818093434 25.190003630415041869 +10.15165971359238 405.6163990423083 33.789335982455668272 +10.37148975417949 405.8803684646264 33.783077011044952087 +12.0010716955876 406.6901133377105 33.741511563301173737 +12.18241358699743 406.7261748481542 33.737113780531217344 +12.83117339585442 406.8113115467131 33.721565309762809193 +13.29875867755618 406.5559565816075 33.711693086032028077 +14.01517911243718 405.8388523114845 33.697939795762067661 +14.22524788940791 405.1608646875247 33.695877275138627738 +14.36998980306089 404.6679981648922 33.69456449045901536 +15.31806151068304 401.2138311527669 33.686917011214973172 +15.15848043421283 399.4771868744865 33.697968835818755906 +14.88845390093047 399.1793620120734 33.705545703567622695 +13.67576247791294 398.7554175294936 33.735725071888737148 +13.11592012050096 398.8444458916783 33.748458006175496848 +12.13463081652299 399.6353938421234 33.768101786241459195 +11.4907712014392 400.6725990129635 33.778807767852413235 +11.08449465525337 401.6680889939889 33.78412678188396967 +10.92545679805335 402.1549022719264 33.785799785619019531 +10.17481925431639 405.2944277450442 33.790150006148905959 +24.09592059464194 404.9350041607395 33.655649064670797088 +23.65366482082754 405.4009651616216 33.652468012895042193 +23.34727713791654 405.5039854748175 33.650342741070289776 +22.69172771042213 405.3030142690986 33.645946016562902514 +21.12705132400151 404.7709973100573 33.635470535049989849 +20.15541586140171 404.367978207767 33.628991401805706118 +20.16600559651852 404.0449997065589 33.62917895499504084 +20.71686616842635 402.0860070129856 33.633633620165710454 +23.80807237396948 402.9879962084815 33.654382442354744853 +24.04598021658603 403.2730010366067 33.655902321814664901 +16.30886730283964 399.0485838828608 37.383880029374267906 +16.05505506973714 400.1230322783813 35.79329137405147776 +16.0527517106384 400.952840895392 34.653746826661517844 +17.05309022823349 401.3127794396132 34.618906202565995045 +18.81781646446325 401.9174010902643 34.599091457086615264 +28.4063362107845 405.1661522341892 34.541396368062123656 +29.48844987957273 405.5208615828305 34.551251482829684392 +29.82462588546332 405.4303451469168 34.82968846065341495 +29.82834649470169 404.3090427070856 36.369809397161589004 +28.90587378223427 403.4075349662453 37.183404198702191934 +28.10649059840944 403.0420899093151 37.31800513707275968 +24.80114753521048 401.763745944947 37.55526928196195513 +17.45412425382528 399.3909041853622 37.439705149954534136 +27.98403379356023 406.2150578461587 33.63974307622629567 +25.19196529197507 405.2919405875728 33.644397773788682571 +25.1099953004159 404.6879919553176 33.645585668971989435 +26.1279870554572 404.5019778413698 33.644840912326117177 +26.54101301380433 404.5990222766995 33.644224354813331956 +28.26099261292256 405.3299873536453 33.641061172168406301 +28.63200675719418 405.5050115659833 33.640347230511792986 +28.5250124570448 405.9220213247463 33.63970118112365526 +31.12578812881839 401.010466940701 34.20225403872973402 +30.14019220275804 400.7123725209385 34.206975818688079016 +28.70433963113464 400.2712514922023 34.213637897622902528 +19.82130767614581 397.3515258030966 34.248815124050452141 +17.51184840325732 396.3741302173585 34.25104779755929485 +18.54598947521299 396.3450231952593 34.235267489064426627 +20.44490156602114 396.9060130519792 34.225747853592110914 +31.02429209568072 400.3983562542126 34.184329492580218357 +12.83047490182798 409.8276979653165 37.301745028627919964 +12.73099151055794 410.045077146031 36.951467148057417944 +12.52860016422346 410.9702720120549 35.564028248874819838 +12.43777488998603 411.5709831416607 34.682175228430423886 +13.68894848483615 412.2667654724792 34.295242627704283223 +16.75632934679743 413.3165501356125 34.263254940509796143 +25.46423992456403 416.198115022853 34.310277851545833983 +25.64967550383881 416.2474643588066 34.328065942827379331 +26.02825473761186 416.2724462365732 34.470251434337114915 +26.98133600945584 414.3280222164467 37.633006195974303409 +17.86789295799099 411.3135268893093 37.582024828647263348 +16.00925202551298 410.7091953996569 37.557012233199202456 +12.70881285716314 409.8854826185852 26.35909908402027213 +12.41799780190922 411.1971517587081 26.35149347089100047 +12.20115599653218 411.415824951604 26.34760929249387118 +11.32714918686543 411.9581288369372 26.332751546116924146 +08.39887227059808 411.120019341819 26.289219659567606868 +07.64131585264113 410.8741035982966 26.278026254425640218 +05.80604593711905 410.2209930438548 26.251043859687342774 +05.20725857350044 409.95696084667 26.242360280382854398 +04.75450039946008 409.606075652875 26.236150299191649538 +04.75511477189139 409.4129826202989 26.236614212870335905 +04.90493087808136 409.1980104669929 26.239448134670965374 +11.0074223926058 408.6692388914526 26.335522219618724193 +11.81245074269827 408.8112345989794 26.347697850069380365 +16.00699518492911 398.2397992908955 31.834022784569242503 +15.72654205991421 398.2219329783693 31.838362203432552633 +15.5600269655697 398.2038861773908 31.840274126569056534 +12.10687672731001 397.4350782707334 31.844675920816371217 +12.31434874620754 396.5305279297754 31.75947836552222725 +12.50871230196208 396.486214382574 31.751406192868671496 +14.80485285457689 396.9366211052984 31.743047333889990114 +15.5045500950655 397.2696780292317 31.757992157066837535 +16.11687475908548 397.9250865774229 31.803582919941618457 +21.24400211707689 415.3649937966838 34.221373337626516786 +20.76801680563949 415.2369507532567 34.221335424372284706 +16.20199049613439 413.7480278508738 34.221259107364630836 +15.49297467514407 413.4630742128938 34.221306525021873313 +14.1950002212543 412.9239993542433 34.221412537064963999 +13.96100540529005 412.6429841602221 34.221634344188714749 +14.22299253626261 412.5490218736231 34.221836523627530369 +14.54503161227331 412.5259073628113 34.221983180784320666 +16.68394469725899 413.2591620618477 34.221979476686499311 +21.62200755579397 414.9989778585732 34.221919139503370388 +16.27177142922301 397.4098354214802 26.380329670930223074 +15.84392641438171 397.373166853562 26.390112569297343725 +09.51510503934696 394.58267401997 26.349077292325091548 +09.62544953019824 394.0914825974032 26.305188237547554309 +10.31081303523388 393.6737568015233 26.250149228435475379 +11.51109791407362 393.9939708076417 26.240662030762905488 +13.8091999044409 394.7544484538957 26.234675300740491366 +16.21612889831886 395.6586443642154 26.237304228587163379 +16.4901551468065 395.7685719421133 26.238180734042543918 +17.11912527575623 397.0248591434211 26.323145475311321206 +16.68454568006564 397.262458274141 26.355791359703289345 +11.93014367308933 408.4866758985445 31.791276846430264413 +09.28215536219068 407.7173936963081 31.75605983633431606 +08.74757413670886 407.4797048456967 31.756121767808508594 +08.61412482708693 407.3882067482919 31.75893703239489696 +09.05170323851053 406.4516927711666 31.857346675777080236 +09.24047374923248 406.1099546290934 31.894379589299205691 +12.85623958439101 407.9982270346954 31.869533666489587631 +13.01573631656356 408.1685248427093 31.860864001089794328 +12.60696733568329 408.3685853499919 31.827674651693087071 +12.5537612909684 408.3870501527563 31.824014113088196609 +26.09436442807782 411.1418359261006 33.613139895019230607 +22.76559876604006 411.1088722394779 33.5871516782008257 +22.39167954714503 411.0465058833361 33.593537769562317408 +21.11190716864076 410.6785701820627 33.639898887096933322 +18.3858401379548 409.5416183434427 33.794679730270217988 +18.06981709052343 409.3120081759989 33.828137343183698249 +18.49924923444632 408.2976987315342 33.993056488779984647 +18.78232809819747 408.2413648013026 34.004646997062991431 +21.8356563069392 408.9238989697769 33.92501590406664036 +22.96910176088568 409.2903643958271 33.877515758465051476 +25.84534085320774 410.4831490581855 33.715286898040176311 +09.43863188964315 405.3597322963178 31.762247841048520058 +09.89115137478802 405.181680591777 31.777478949341457337 +10.17826394399162 404.8533465769142 31.783940076376893558 +10.37235267239157 404.6110035898164 31.788004619942512363 +10.6306758383289 403.8708779914305 31.787204625259619206 +11.89047611737624 399.4353083558381 31.771018473955336958 +12.08489108085632 398.7040881551802 31.767825920222094283 +12.03206044901162 398.6396463699639 31.764780301818973385 +11.79601710278075 398.3573828209192 31.751256837189430371 +11.32837305520661 398.8131404118612 31.739557866923860274 +11.09322579344735 399.108837752603 31.734664536954369396 +09.60053287597839 404.0732005666941 31.749512755166506395 +22.38012466148939 410.2717697853222 35.512808224564651027 +21.76535009255167 410.0583534762263 35.515353234756730672 +21.16399827261921 409.8030031882226 35.516850234233061201 +18.70914852875285 408.7097257077694 35.521877533411498007 +18.88266742322594 408.4416141761467 35.514165402064463706 +19.26781342586037 408.446344550699 35.509823906101701141 +19.40485333825927 408.4482708433643 35.508284325263048231 +19.52424465096556 408.4625481972471 35.507211379973341536 +22.42845231422689 409.3311647009104 35.492215933744773793 +22.51874839002267 409.519464654848 35.495185251558723394 +07.66731075686403 405.9165781596676 26.045615110313519835 +08.10775040811859 406.0468677319586 26.191244866116903722 +08.62209367996547 406.193032508716 26.360687590204179287 +09.38062976091169 405.1466660387814 26.479257534607313573 +12.16817101661582 396.1632100148126 26.380301777506247163 +12.08555225213058 395.6253103781492 26.299552559503354132 +11.72506791120395 395.4042473118752 26.168452374171465635 +10.39215060905553 396.7210750905797 25.905791483819484711 +07.82994132814929 405.2935093222186 26.029544222517870367 +05.59181280178018 406.697630411014 26.130241364473477006 +05.71033744746819 406.9111389126629 26.420678965747356415 +05.96792367403395 406.9424428027123 26.832983688684180379 +06.0822843904607 406.6657573990524 26.869036767864599824 +06.74939188617282 404.9568413356319 27.031335173873230815 +07.58642286830582 401.6892724130303 26.666695349849760532 +07.28482181811705 401.8848574198782 26.301421149633824825 +06.01104488689452 405.4353220108896 26.136943868827074766 +05.81004733382724 405.9985682694241 26.112505188211798668 +15.04790493741166 404.5012912554666 37.477588657115120441 +14.64020109013654 404.7543642893434 36.944467098408495076 +14.30796716420446 405.8120464729145 35.34264787744905334 +14.3989862886956 406.265977458097 34.761845092114526778 +16.45279925479554 407.2056752191857 34.411195288426824845 +16.91541617247276 407.3847473813221 34.376898264425108209 +24.54904939758126 409.8888082224876 34.429038441114244051 +27.74898807646241 410.9189691953361 34.477650952685507946 +28.57294878060929 409.8112522726879 36.372579813105403446 +28.25475491897669 409.1197040956467 37.175444313543266617 +27.10640522127505 408.5657455120236 37.410639556153910235 +25.8794661895372 408.1435740171 37.429266919891233556 +24.60806292074267 407.7107849912718 37.44215016947418917 +07.38440433656797 400.9313132427633 26.120383454253897071 +07.23960742726922 401.7865592353046 26.324537456966936588 +07.53420250117779 401.793233146891 26.672524284571409225 +07.71495402022265 401.7367494972423 26.859560764161869884 +08.1986744357273 401.4598023481667 27.305128939915448427 +08.89351076516323 399.9361853413284 27.453164787497371435 +10.28881558030844 394.8661671532318 26.871835514204576612 +10.03704017028213 394.8759261742234 26.581186483148485422 +09.8059262256138 394.8859698623419 26.31486340262927115 +09.43845552066341 395.0240454431623 25.944773125695064664 +09.66778644081205 403.4647348187864 26.337618718344856461 +08.8997445841087 403.6956828441471 26.333443882085703081 +07.06372075318359 406.8888949789107 26.351912883042132307 +06.69527769403066 407.9611030938104 26.360266123376277392 +06.77834777918179 408.258190119639 26.364186821667317417 +08.09166745655239 408.8183453446254 26.381613183995796135 +09.03677122516092 409.2159576499835 26.394094553454124252 +09.20211365749128 409.2243828577921 26.395619596917640592 +09.61370015062857 409.0736276702955 26.397566103636563639 +15.4682791858213 399.2634038729593 31.479548230476211756 +14.80883755779359 399.1494604777545 31.433286550818593241 +13.06189165648539 398.7613800894469 31.341803388626431115 +12.61210298794322 398.039652923122 31.542296807514503598 +12.4739399967948 397.646624116227 31.665617381368065253 +12.69228640513029 397.4224994368851 31.775284764531534165 +13.17649666231591 397.4756484823301 31.820249089199933223 +15.15018516452983 398.2171205608174 31.814422523078974336 +15.87209138239268 398.5394725268707 31.793862094564246945 +28.47482733079232 408.4539570054039 37.457226056736544706 +26.64186012768187 408.0440455144271 37.7303463601419935 +23.92127509554848 407.1618094155565 37.758067429982475005 +15.51361764210742 404.209619323723 37.532395488669862971 +14.98390895675402 403.7298531495035 37.113011360270320438 +15.13680858619045 402.519411591813 35.373628491215640679 +15.62003063806333 402.1724260812625 34.674021707149222493 +15.90693419333547 402.0676498580724 34.398273581871762872 +17.4373902019579 402.5643118815497 34.383179915108485147 +28.92778840148821 406.4030059529468 34.421353010489838198 +29.09841634274926 406.6933534517884 34.74374837864888832 +29.10631852201186 406.7495580958202 34.817651046163518913 +29.11926705250517 407.2447516089305 35.494698643509764224 +28.85813654132653 407.9069043342024 36.527390699804527685 +30.26375315745827 403.1060210810974 37.419273910403717309 +29.72118894685991 402.9403491765261 37.441250081261387095 +27.37703220266849 402.1986325215548 37.500426853759563528 +17.94393827067688 399.0468268487602 37.508064336841925979 +16.60063665651251 398.3095294414088 37.111174231307813898 +16.5283750644885 397.9964971924201 36.712679079661029391 +16.83965840144083 396.9415150415152 35.11347122787265107 +17.02770575834438 396.5115091884509 34.433395225365529768 +17.30162658600602 396.5665348675102 34.38282125124533195 +19.63386923552025 397.2746989382431 34.282856459161848761 +22.84955634304788 398.3093501618132 34.225370394095079973 +25.13768680905923 399.1083672726527 34.271117255120771006 +30.171610408579 400.8717804849148 34.379435587601619773 +30.79252238594927 401.1926858900115 34.535442984124529175 +30.86113985301927 401.2371999248862 34.565169709268957376 +30.44147782737855 402.8868560073897 37.034843245564843528 +25.9360053059645 413.545240602456 37.482975690931198187 +21.52375787985511 412.1020318977535 37.510900912238867022 +14.98278726264834 409.9073546351865 37.475929563224781305 +13.82306245248765 409.5052645234391 37.451778643415309489 +13.1865007460583 409.1682788869366 37.27759104227880016 +12.9883900124114 408.9704278400168 37.094706454357947223 +13.51134748803452 407.5007107844576 34.820614318232401274 +13.54922282882035 407.4640715504065 34.752521318441722542 +13.82592372654472 407.5069092074409 34.684797710651764646 +14.86175025370903 407.6851303623989 34.455991395661840215 +15.38129317294806 407.8126745382324 34.394031222997000441 +26.57955647364724 411.2675523795187 34.035319927003001794 +27.20708823762834 412.062462261878 34.84740668126323726 +26.88831128063612 413.6024539070204 37.125035057601053268 +4 0 1 2 3 151 47 171 255 +11 4 5 6 7 8 9 10 11 12 13 14 104 165 85 255 +13 15 16 17 18 19 20 21 22 23 24 25 26 27 57 123 160 255 +10 28 29 30 31 32 33 34 35 36 37 170 81 74 255 +4 38 39 40 41 122 40 149 255 +4 42 43 44 45 75 158 63 255 +4 46 47 48 49 188 116 138 255 +4 50 51 52 53 141 74 52 255 +4 54 55 56 57 93 32 127 255 +4 58 59 60 61 46 150 41 255 +4 62 63 64 65 159 108 116 255 +4 66 67 68 69 112 67 190 255 +4 70 71 72 73 64 185 105 255 +14 74 75 76 77 78 79 80 81 82 83 84 85 86 87 177 143 179 255 +14 88 89 90 91 92 93 94 95 96 97 98 99 100 101 130 101 94 255 +12 102 103 104 105 106 107 108 109 110 111 112 113 83 59 168 255 +11 114 115 116 117 118 119 120 121 122 123 124 35 177 83 255 +19 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 148 135 157 255 +10 144 145 146 147 148 149 150 151 152 153 101 94 71 255 +13 154 155 156 157 158 159 160 161 162 163 164 165 166 53 52 146 255 +8 167 168 169 170 171 172 173 174 166 170 60 255 +8 175 176 177 178 179 180 181 182 119 128 135 255 +12 183 184 185 186 187 188 189 190 191 192 193 194 72 86 49 255 +13 195 196 197 198 199 200 201 202 203 204 205 206 207 184 44 124 255 +9 208 209 210 211 212 213 214 215 216 137 163 38 255 +10 217 218 219 220 221 222 223 224 225 226 90 121 113 255 +11 227 228 229 230 231 232 233 234 235 236 237 43 79 187 255 +10 238 239 240 241 242 243 244 245 246 247 155 37 102 255 +11 248 249 250 251 252 253 254 255 256 257 258 108 155 176 255 +12 259 260 261 262 263 264 265 266 267 268 269 270 61 113 91 255 +10 271 272 273 274 275 276 277 278 279 280 174 71 165 255 +9 281 282 283 284 285 286 287 288 289 126 190 80 255 +9 290 291 292 293 294 295 296 297 298 79 148 154 255 +13 299 300 301 302 303 304 305 306 307 308 309 310 311 32 106 69 255 +10 312 313 314 315 316 317 318 319 320 321 144 64 143 255 +9 322 323 324 325 326 327 328 329 330 97 182 58 255 +9 331 332 333 334 335 336 337 338 339 50 140 132 255 +14 340 341 342 343 344 345 346 347 348 349 350 351 352 353 163 99 47 255 +16 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 115 57 121 255 +14 370 371 372 373 374 375 376 377 378 379 380 381 382 383 68 175 36 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-a.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-a.off new file mode 100644 index 00000000000..2de3cad395c --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-a.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-b.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-b.off new file mode 100644 index 00000000000..c972a30fc1f --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-b.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-c.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-c.off new file mode 100644 index 00000000000..f5175b2243d --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-c.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-d.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-d.off new file mode 100644 index 00000000000..ac314dd7a63 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-1-polygon-d.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ab.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ab.off new file mode 100644 index 00000000000..f40d86622cb --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ab.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ac.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ac.off new file mode 100644 index 00000000000..7209a862c78 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ac.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ad.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ad.off new file mode 100644 index 00000000000..946715669b8 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-ad.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bc.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bc.off new file mode 100644 index 00000000000..e498cc3a5c6 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bc.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bd.off new file mode 100644 index 00000000000..bffeae4f25c --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-bd.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-cd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-cd.off new file mode 100644 index 00000000000..3b52d73e26a --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-2-polygons-cd.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abc.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abc.off new file mode 100644 index 00000000000..ed95db6f867 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abc.off @@ -0,0 +1,17 @@ +OFF +12 3 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abd.off new file mode 100644 index 00000000000..18fc4c0273e --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-abd.off @@ -0,0 +1,17 @@ +OFF +12 3 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-acd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-acd.off new file mode 100644 index 00000000000..cce0847fcf3 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-acd.off @@ -0,0 +1,17 @@ +OFF +12 3 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-bcd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-bcd.off new file mode 100644 index 00000000000..cd6a1c580ad --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-3-polygons-bcd.off @@ -0,0 +1,17 @@ +OFF +12 3 0 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-4-polygons-abcd.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-4-polygons-abcd.off new file mode 100644 index 00000000000..919da0b8db9 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-4-polygons-abcd.off @@ -0,0 +1,22 @@ +OFF +16 4 0 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 +4 12 13 14 15 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-6-polygons.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-6-polygons.off new file mode 100644 index 00000000000..3f0d056b0d8 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-0/test-6-polygons.off @@ -0,0 +1,32 @@ +OFF +24 6 0 +0 0 0 +0 0 1 +0 1 1 +0 1 0 +-0.41184309124946594 0.860099196434021 1.3924243450164795 +-0.2315056324005127 1.2603075504302979 0.4939190149307251 +-1.2075642347335815 1.220183253288269 0.28014403581619263 +-1.3879016637802124 0.81997495889663696 1.1786493062973022 +-1.5139358043670654 -0.23819819092750549 0.087010979652404785 +-1.4838567972183228 -0.25608164072036743 1.0863984823226929 +-1.6605820655822754 0.72791147232055664 1.1093254089355469 +-1.6906610727310181 0.74579495191574097 0.10993790626525879 +-0.22395908832550049 -0.30043560266494751 1.3847332000732422 +-1.2098929882049561 -0.35027864575386047 1.5442636013031006 +-1.2339011430740356 0.63655495643615723 1.7042105197906494 +-0.2479671835899353 0.68639802932739258 1.544680118560791 +-0.56098687648773193 0.64675056934356689 0.13323120772838593 +-1.3206864595413208 -0.0034976601600646973 0.12742726504802704 +-1.9354726076126099 0.71762150526046753 -0.19198636710643768 +-1.175773024559021 1.3678698539733887 -0.1861824095249176 +0.14283668994903564 -0.38020235300064087 0.41061314940452576 +-0.5413280725479126 -0.38269975781440735 1.1399362087249756 +-1.2631766796112061 -0.52322244644165039 0.46230223774909973 +-0.57901191711425781 -0.52072501182556152 -0.26702100038528442 +4 3 0 1 2 +4 6 7 4 5 +4 10 11 8 9 +4 14 15 12 13 +4 18 19 16 17 +4 22 23 20 21 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-1-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-1-rnd-polygons-1-4.off new file mode 100644 index 00000000000..8342526e34b --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-1-rnd-polygons-1-4.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +0.15610991754831515799 0.24730995207178518847 0.75806682915926948407 +0.16496709986145913218 0.18982328490637073726 0.70621064409094358449 +0.20220499043408207696 0.20800513642778320489 0.71143331797136521999 +0.16105327970812033378 0.2435329721365592226 0.75344213477059684969 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-2-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-2-rnd-polygons-1-4.off new file mode 100644 index 00000000000..83b0b3af944 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-2-rnd-polygons-1-4.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-0.27848521200095188721 -0.17362065704985990555 -0.48022333651203907845 +-0.20910287047394182647 -0.20831641286430413462 -0.53964773517772191003 +-0.2134526329908462694 -0.33174234165134169894 -0.5522901251270546652 +-0.31416959136675037811 -0.26137648424083415044 -0.46342192033603812895 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-3-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-3-rnd-polygons-1-4.off new file mode 100644 index 00000000000..3e664b565b4 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-3-rnd-polygons-1-4.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +0.6058591159546817817 -0.56965501181620259441 -0.29382108215188745826 +0.71027544352893468016 -0.63504842208265066539 -0.24922269226626372896 +0.63486095745100423748 -0.62410903622118019118 -0.27462002163464782623 +0.5875997816478347735 -0.61217025573008843065 -0.29149056082363838938 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-4-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-4-rnd-polygons-1-4.off new file mode 100644 index 00000000000..352de472227 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-4-rnd-polygons-1-4.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +0.65774115146030065482 -0.66588743441438869031 0.27077692585696377936 +0.65483141298809188768 -0.64671837624026129454 0.22277241439658501676 +0.66734344616877083745 -0.63810531966829220352 0.20761055052755555961 +0.66426225766577595699 -0.65297632519401094253 0.24237630508545701669 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-5-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-5-rnd-polygons-2-4.off new file mode 100644 index 00000000000..dcb664cd5ee --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-5-rnd-polygons-2-4.off @@ -0,0 +1,11 @@ +OFF +7 2 0 +-0.75586385340622519458 1 -0.23672909840242375989 +-0.89154339425773576622 1 -0.37805786411577557704 +-0.88250651732241514047 0.78626208915370920938 -0.36670801179005296788 +-0.59348480160629835112 -0.74056950060417792159 -0.2050942961146551835 +-0.58102610551155020602 -0.83393195226800997943 -0.15380965246301198102 +-0.56262801769830761422 -0.86362049050797007332 -0.13372370148604620366 +-0.55289320769567962266 -0.81624109559911572909 -0.15554750188514177012 +3 0 1 2 +4 3 4 5 6 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-6-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-6-rnd-polygons-2-4.off new file mode 100644 index 00000000000..d5390c7d853 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-6-rnd-polygons-2-4.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.3277950810341435095 -0.71572519555741642705 1 +0.44583319221311557001 -0.55783953841437650123 1.000000000000000222 +0.49792905888093180744 -0.56261138383018360898 0.95733761618227708468 +0.35294980452977714469 -0.7302358935204456003 0.97240589188409809474 +-0.2346615724500573652 0.2359083322962581275 -0.86630763542970434798 +-0.17518768997739564419 0.25326623936895609202 -0.82117173852959646219 +-0.20624273406363702321 0.24040269900916738655 -0.83899000079087826531 +-0.31450806115767204751 0.2041965275375098865 -0.91418165777420656859 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-7-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-7-rnd-polygons-2-4.off new file mode 100644 index 00000000000..fd1a8c2eb90 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-7-rnd-polygons-2-4.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.42664258079485539721 -0.64018711292148333669 -0.8515757057538347885 +0.47128039048102887687 -0.69117967554445147726 -0.63642214593465173955 +0.46521352858576825451 -0.6847858061697209564 -0.59387621079444419259 +0.39467662025607563869 -0.60557076789227659575 -0.75145416500478101618 +-0.61128424188107577386 -0.0065553514480266306119 0.12041273689470853581 +-0.60307712410684555238 -0.015813165312354077185 0.10456127944179721689 +-0.52365439684733239289 -0.036618358574756329493 0.10431565172664833407 +-0.56077586454367644997 0.0030584121888515419796 0.17112120108282907749 +4 0 1 2 3 +4 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-8-rnd-polygons-3-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-8-rnd-polygons-3-4.off new file mode 100644 index 00000000000..d4416960a73 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-1/test-8-rnd-polygons-3-4.off @@ -0,0 +1,17 @@ +OFF +12 3 0 +0.41186711452985735882 -0.84447415301680273103 0.61971905157646700602 +0.3726672154490638933 -0.82005456375273910741 0.57833709628588936269 +0.43379958596908135826 -0.77821018652431572793 0.53965070351019428507 +0.45953807659864553958 -0.85201997202192947256 0.64143687269748617119 +0.56524011840538745943 -0.9269854143534064228 -0.93732252277842953436 +0.53001528833590116907 -0.88197115046793839177 -0.80305925948165446382 +0.5343169664938652863 -0.8813615647683934462 -0.76975034913882212084 +0.58688152844940888464 -0.93327180618593374994 -0.84587700839017732068 +0.84617929803296143554 -0.075606934264453112826 -0.45154586920481221135 +0.84257074360400219248 -0.049825902960862020197 -0.49619010373477290265 +0.84551728503647649582 -0.043649377875797881754 -0.5046759664229832909 +0.85188434368617060866 -0.057012532939158339085 -0.47892803304073455761 +4 0 1 2 3 +4 4 5 6 7 +4 8 9 10 11 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-1-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-1-rnd-polygons-1-4.off new file mode 100644 index 00000000000..07c705638b7 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-1-rnd-polygons-1-4.off @@ -0,0 +1,8 @@ +OFF +5 1 0 +-0.66508574846829815463 1.000000000000000222 1 +-1 1.000000000000000222 0.29568263728738397589 +-1 0.49897796883298217718 -0.11978312174973984594 +-0.55660743371016518921 -0.16149819747870888809 0.26497082067774524461 +-0.6084138559251720535 0.85627772973828997216 1 +5 0 1 2 3 4 151 47 171 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-2-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-2-rnd-polygons-1-4.off new file mode 100644 index 00000000000..c0a2748c4da --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-2-rnd-polygons-1-4.off @@ -0,0 +1,8 @@ +OFF +5 1 0 +0.22199248907356433635 0.38234721541755123386 -0.40145544621769113647 +-0.16310117977085047958 0.33839070297855550207 -0.67649397701646463155 +0.54142965320095326476 0.11968280838115723241 -0.59326324340446001671 +1.000000000000000222 0.053701914675631429175 -0.43186632245303618882 +1.000000000000000222 0.14056359227637085785 -0.30991834223072101118 +5 0 1 2 3 4 151 47 171 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-3-rnd-polygons-1-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-3-rnd-polygons-1-4.off new file mode 100644 index 00000000000..1a01d2bb749 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-3-rnd-polygons-1-4.off @@ -0,0 +1,8 @@ +OFF +5 1 0 +-0.55990680617290000676 -0.31687801053428754638 -1.000000000000000222 +-0.29966590024503708678 -0.68176527196857317215 -0.6438155321085256011 +-0.23989802816964495014 -0.68926183670651930413 -0.61289408431803793498 +-0.22826065730695549449 -0.44086473021631966684 -0.77348164105171091087 +-0.52861453414917458637 -0.29652433388882448728 -1.000000000000000222 +5 0 1 2 3 4 151 47 171 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-4-rnd-polygons-1-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-4-rnd-polygons-1-3.off new file mode 100644 index 00000000000..7d495246822 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-4-rnd-polygons-1-3.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-0.48289007545713447112 -0.61238641185731346184 -0.86469797977928597454 +-0.80950276482308491932 -1 -0.16276171016941476388 +-0.83915985241456136912 -1.000000000000000222 -0.0096588397408848350456 +-0.092097972413576381645 0.45417658189572263083 -0.17405046706790600064 +4 0 1 2 3 151 47 171 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-5-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-5-rnd-polygons-2-4.off new file mode 100644 index 00000000000..9c727003ca7 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-5-rnd-polygons-2-4.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +0.82247803392408824763 -0.38723958396306096263 0.71483223598611078664 +0.4371395289299538911 0.41385223399823467538 1 +0.7768629544902037054 -0.067486358150455449945 1 +-0.52490807106371173418 0.70202499736418966236 -0.75131148071949449552 +-1 0.14887624923234760166 -0.97841040882785967892 +-1 0.12973035450051789708 -0.9952241441222685614 +-0.40768718176727042346 0.58297646639260447543 -0.91968136980637482658 +-0.44764602127526076369 0.75497110588690130584 -0.74688119809810737948 +3 0 1 2 +5 3 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-6-rnd-polygons-3-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-6-rnd-polygons-3-4.off new file mode 100644 index 00000000000..c225174f3c4 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-2/test-6-rnd-polygons-3-4.off @@ -0,0 +1,19 @@ +OFF +14 3 0 +-1 -0.1308931904985670136 -0.33516365222314192795 +-1 -0.6714824653370352614 -0.46095306936059748937 +-0.53132660948762833186 -1 -0.49330740560611507917 +0.057623176177123244801 -1 -0.43790474847955712656 +0.12944421667994215897 -0.59071019190416351741 -0.33591110742787727572 +-0.42911398666181577166 0.07466508181731418281 -0.23362901893928705865 +0.7067437544383333714 0.37344944179068317869 -0.036158806509220278724 +0.91313952580497859124 -0.012979918910328319681 -0.69007115976925992307 +0.77787066773300050926 -0.78971672987692920209 -0.62288835681625798202 +0.48017540496484628632 0.47262447393840950616 0.5676285342638573983 +0.30269300459096654121 0.65614771078703726381 -0.4545514736489389418 +-0.15148149240820321659 -0.053039606746919661096 -1 +0.64392628567208598511 0.48307410642363313169 -1 +0.6903559188209320574 0.92904220194979114655 -0.43884663379571980935 +6 0 1 2 3 4 5 +4 6 7 8 9 +4 10 11 12 13 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-1-rnd-polygons-2-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-1-rnd-polygons-2-3.off new file mode 100644 index 00000000000..6fe075acbc4 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-1-rnd-polygons-2-3.off @@ -0,0 +1,13 @@ +OFF +9 2 0 +-0.76493907384012427286 1.000000000000000222 0.77243260997077778374 +-0.45140411323920476283 1.000000000000000222 0.43172219910796783005 +-0.13431377427363866417 0.7907631996323489787 -0.092352722151927968408 +-1 0.34026961369270730673 0.46189493876274467787 +-1 0.76006911279018973815 0.82203434977762390723 +-1 0.11657020090119979416 -0.065554122581789067703 +-1 -0.0054723979577700077731 0.014022945467475884593 +-0.95051199506759909141 -0.56363750391437550391 0.34491514379739784957 +0.37343330580552425157 -0.6855170465483748643 -0.45994733771416640433 +5 0 1 2 3 4 +4 5 6 7 8 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-10-rnd-polygons-5-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-10-rnd-polygons-5-4.off new file mode 100644 index 00000000000..d56d45cb334 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-10-rnd-polygons-5-4.off @@ -0,0 +1,32 @@ +OFF +25 5 0 +-0.35937495820139497837 1 -1.000000000000000222 +-0.56168365686147958549 1 -0.88079113017468313451 +-0.51765631751223795121 0.71236096709012564077 -0.73280279939922654542 +-0.32201075440850046583 0.41207376422586394771 -0.66650619669355770647 +-0.24485654838122550281 0.81187983031110944054 -0.95372559705916493122 +-0.30870221019199428625 0.95062137083057174358 -1 +-0.92634822138016548188 0.32081332010057639348 -0.89166385180227825114 +-0.65046206980728782376 -0.14506803516911384588 0.1349183917820096501 +-0.90687582408461064887 -0.55696720534041499473 -0.020160895165416414798 +-1 -0.49262635780542279873 -0.27880641108149650798 +-1 -0.085148195619931407729 -0.6641707630162561049 +-1 -0.41326725544380638055 -0.36778153643664412975 +-0.82904255842645513397 -0.65731436296472334213 -0.072082412778263660336 +-0.88802569218386917527 -1 0.094015865785319951975 +-1 -1 0.00073472792471934722514 +-0.28493565917010799105 -0.81230567244099638469 0.3037669232785958906 +0.27084247530824534511 0.24191842674958360937 -1 +0.4820710256500247981 0.409847753407221016 -1 +-0.23633151774247695975 -0.82319359663389457538 0.40921569357703219127 +-1 -0.28251564915131083255 0.11078989440908593167 +-1 0.75867918699380421099 0.82693688741610604787 +-0.85576724261093495283 0.74232635514938138943 1.000000000000000222 +-0.71833701121485060703 0.486998038301589109 1 +-0.75383346694464692384 0.096118113082173745054 0.68578796121348406523 +-0.89033230213133696118 -0.5108053106028178636 0.093910499149422357879 +6 0 1 2 3 4 5 +5 6 7 8 9 10 +4 11 12 13 14 +4 15 16 17 18 +6 19 20 21 22 23 24 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-2-rnd-polygons-2-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-2-rnd-polygons-2-3.off new file mode 100644 index 00000000000..05b1c944acd --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-2-rnd-polygons-2-3.off @@ -0,0 +1,14 @@ +OFF +10 2 0 +0.065178480926116666438 1 -0.20264199478017669298 +-0.10659096293787867493 1 -0.99999999999999988898 +-0.082990164860711909678 0.73167804164683836188 -1 +-0.066163058435701305182 0.61774449366182171417 -0.96840706757492145407 +0.39731238540939262105 0.095576446776173107356 0.96985690312632977239 +-1 -0.55362335819508701196 0.96499401999985501277 +-0.73419017118209328743 -1.000000000000000222 0.42819404217768131105 +-0.35962148959437645335 -1.000000000000000222 0.67195886059086873399 +-0.74144277975571681871 -0.637429111257047043 1 +-1 -0.53160847565811986115 1 +5 0 1 2 3 4 +5 5 6 7 8 9 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-3-rnd-polygons-2-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-3-rnd-polygons-2-3.off new file mode 100644 index 00000000000..95be8af6232 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-3-rnd-polygons-2-3.off @@ -0,0 +1,13 @@ +OFF +9 2 0 +-0.84361004019701402168 -0.65130254444935298253 1 +-0.95423896077224912293 -0.50938438578589595451 0.69781052627559669865 +-1 -0.55430483193732538183 0.64158495303585083569 +-1 -0.69336060090569506809 0.73387372724361377152 +-0.86883463768205282385 -0.72276222859077143834 1 +-0.25796910527514543832 1.000000000000000222 0.054658922434833369375 +-0.066746659167777860899 -0.16823609427621460943 0.36926899081650771395 +-0.24439833879466932309 0.92947306772009130604 1 +-0.25590097132239597588 1.000000000000000222 1 +5 0 1 2 3 4 +4 5 6 7 8 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-4-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-4-rnd-polygons-2-4.off new file mode 100644 index 00000000000..c08e5cc52b0 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-4-rnd-polygons-2-4.off @@ -0,0 +1,14 @@ +OFF +10 2 0 +0.99395946670045409732 -0.60484981715831964699 1 +0.082000690456150326924 0.12862242584613770013 1 +0.11251197455782492585 1 -0.07986612560595388044 +0.40482642634579113494 1 -0.36324063342911483421 +1 0.63472626351812611034 -0.49994044031475315393 +1 -0.59792896677548235118 0.98580237350131394436 +0.38334599303813665649 -0.046781085286543885871 -1 +0.82632443446521053332 0.40968638946239865906 -0.57274494339167314472 +1 0.31767600361817982524 -0.69552390095880878285 +1 0.033459285003822773763 -1 +6 0 1 2 3 4 5 +4 6 7 8 9 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-5-rnd-polygons-1-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-5-rnd-polygons-1-3.off new file mode 100644 index 00000000000..0acc28a20cc --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-5-rnd-polygons-1-3.off @@ -0,0 +1,7 @@ +OFF +4 1 0 +-1 0.050837722027102974498 0.54505759599567538132 +0.16811988199649041675 0.80151514898576281531 -0.40109844110374870407 +-0.58818491486273871693 0.31521669829332493729 0.21741677816456833616 +-1 0.050730632041863517323 0.54741721763029804748 +4 0 1 2 3 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-6-rnd-polygons-2-3.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-6-rnd-polygons-2-3.off new file mode 100644 index 00000000000..bc807063028 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-6-rnd-polygons-2-3.off @@ -0,0 +1,14 @@ +OFF +10 2 0 +-1 0.030045090724081961048 -0.13245310112330005436 +-0.15988174854623449228 -0.053663372801941000567 -0.24395348495693491842 +0.20856755520811867677 -0.20955867925969323684 1 +-0.42251405587732343561 -0.13895714421134214289 1 +-1 -0.045583618398000957939 0.68793685321320441339 +0.34148803330388094457 0.45290081304230628279 -1 +-0.0019946781954731521505 -0.54523601993875181471 -0.45249651637909066304 +1 -0.73388441054823971843 0.46529063840734929958 +1 0.12075133383802641451 -0.22796759125806756452 +0.62913514637166012555 0.72354959198817503374 -1.000000000000000222 +5 0 1 2 3 4 +5 5 6 7 8 9 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-7-rnd-polygons-2-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-7-rnd-polygons-2-4.off new file mode 100644 index 00000000000..b69b73d2cc9 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-7-rnd-polygons-2-4.off @@ -0,0 +1,13 @@ +OFF +9 2 0 +0.21014951485263619335 1 0.88322417841893186008 +-0.80833788025653663389 1 -0.3903756888948147763 +-0.91308199916295884613 0.46390556084368345102 -1 +-0.17215345807450577187 -0.57382025641791567505 -1 +0.46663273709075830942 0.48797826485366435634 0.74680099826306656219 +-1 1 0.57313255164517351581 +-1 0.54861250776213532632 0.01191340639967708448 +-0.51534558532781971074 0.83882461852285628012 0.65873530482115905116 +-0.64253052892012707531 1 0.78407585863525697256 +5 0 1 2 3 4 +4 5 6 7 8 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-8-rnd-polygons-2-10.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-8-rnd-polygons-2-10.off new file mode 100644 index 00000000000..30dd38d93ba --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-8-rnd-polygons-2-10.off @@ -0,0 +1,12 @@ +OFF +8 2 0 +1 -0.18032788943244038027 -1 +1 -1 -0.62043922092690551029 +0.46774636865127655616 -1 -1 +-0.60803313547406756534 0.92278262536235888813 0.31030950273307777998 +-0.074786157769665961847 0.69086312870825294929 0.42312887536103316322 +0.88258564703627984116 0.4189583808595845893 1 +-0.2422025097226233048 1 1 +-0.68251042711498965954 1 0.41069115005829937015 +3 0 1 2 +5 3 4 5 6 7 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-9-rnd-polygons-4-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-9-rnd-polygons-4-4.off new file mode 100644 index 00000000000..51fa7e0929f --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-3/test-9-rnd-polygons-4-4.off @@ -0,0 +1,23 @@ +OFF +17 4 0 +-0.59927801135997582627 0.054423761118229552203 -0.12361202917057637074 +0.33832899450009945586 0.34180695431538510309 -0.88320153093211084538 +0.55809619306034807806 0.2161012005285471993 -1 +0.97496969797187027496 -0.72078719735808149949 -1 +0.9163996679067800688 -1 -0.86967515528330574526 +0.34195859898220892781 -1 -0.46015125039554727326 +0.92125003698889240678 -1 0.080719083865852497839 +1 -0.90164933058389584719 0.013373242912551153161 +1 -1 0.13705569297706979293 +-0.14178338317944827462 -0.3652723792320966556 0.83367757030327360734 +-0.43643519781711792582 -0.99999999999999988898 0.50479077088635593284 +-0.56007763899565277121 -1 0.91840637866040641946 +-0.51072334963738752478 -0.8808852428280217195 1 +-0.14009353589600781476 -0.28223585199477130292 1 +-0.9705898296613374443 0.072163451161779190723 0.11837352551837125592 +-1 0.2796136648060683072 0.23899121544953688678 +-0.99999999999999988898 0.22652888809555332683 0.21314102147935104492 +6 0 1 2 3 4 5 +3 6 7 8 +5 9 10 11 12 13 +3 14 15 16 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-1-rnd-polygons-2-6.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-1-rnd-polygons-2-6.off new file mode 100644 index 00000000000..078094f1957 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-1-rnd-polygons-2-6.off @@ -0,0 +1,13 @@ +OFF +9 2 0 +0.04592020327577803207 -0.92473712134298158283 -0.10204495476006578136 +0.93580989228502475807 0.45036944155644575982 -0.23927111881850338104 +1 0.4913677706800226308 -0.27229956184809461783 +0.99999999999999988898 -1 -0.86508570849756161181 +0.016483382794031872787 -1 -0.10934073037520947169 +-0.43938321811258473915 -0.41058405164472389082 0.67650709033740252796 +-1.000000000000000222 0.95898111697777688178 -0.15663746870248965171 +-1 -1.000000000000000222 0.43012998993532880476 +-0.34980136587230392653 -1.000000000000000222 0.92063254112484982361 +5 0 1 2 3 4 +4 5 6 7 8 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-2-rnd-polygons-3-8.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-2-rnd-polygons-3-8.off new file mode 100644 index 00000000000..bb8cf2ee074 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-2-rnd-polygons-3-8.off @@ -0,0 +1,25 @@ +OFF +20 3 0 +-0.041136787858694082165 0.10169415400705132668 -1 +0.66024800308791609105 -1 -1 +1 -1 0.076373139665307260282 +1 -0.76733277287752810203 0.54565238478165234426 +0.36711295045044056717 0.051890849170681388469 0.19293080246793398169 +0.021476723311123921412 0.11318570011392727059 -0.7784553162836537199 +-1 0.26140655961523528994 0.90242863773611692313 +-1 1 0.026632628846286948709 +0.39992008604188844512 1 0.049046679766118733701 +0.096003555953658198385 0.779182155085341277 0.30601808890623055648 +-0.42651436860343072688 0.43436319760769237508 0.70652528482593535131 +-0.44986205244852928153 1 0.42111059568436093326 +0.076153314839546334958 1 -0.8878228055594648005 +0.097224068626571957807 0.90798112203163694467 -1 +0.065770681947035863901 0.78743231566586968651 -1 +-0.15393413642935208085 0.4289275000565445084 -0.68605338312455188543 +-0.34100876443073602218 0.21180397163506028968 -0.36150926602606126004 +-0.42114289714411812238 0.37635121319937747675 -0.055268818856361895397 +-0.45654739430498381125 0.65162035359132197687 0.21155480135414206355 +-0.47307071660059962781 0.9466016728407951053 0.44419309799809181261 +6 0 1 2 3 4 5 +5 6 7 8 9 10 +9 11 12 13 14 15 16 17 18 19 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-3-rnd-polygons-4-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-3-rnd-polygons-4-4.off new file mode 100644 index 00000000000..8e1064cf24e --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-3-rnd-polygons-4-4.off @@ -0,0 +1,23 @@ +OFF +17 4 0 +0.84488390377294519951 -0.68284952340081683797 1 +0.86641741714329612023 -0.77082927236669984694 0.60352060686775832465 +0.9121288410152565973 -0.72952161179574059879 0.76350747230545468192 +0.89566568009956504248 -0.71539523907881052978 0.83326393608111781752 +0.85168505448751063991 -0.6821236357081662538 1 +0.79682933348847195809 -1.000000000000000222 1 +-0.34791801239959296854 -0.28764156042861477314 1 +-0.299327523245019822 0.60093975914093267221 0.11142468738453970012 +1 -0.25852980189441154835 0.16066698604451506993 +1 -1 0.87773152880361726691 +-0.17838891690765840137 0.83420160017091160576 -0.0018095684143322131841 +-0.89030839343594470048 -0.53933548311667733888 0.025633427611447195255 +-0.48343258035503122727 -0.15341484353582110489 0.80649160552105070288 +-0.12894874426582667026 0.59311027229066026756 0.66787334512323059954 +-0.029780379789940497615 0.38045922161658057847 -1 +-0.09773715311854092036 0.77676442434007964 -1 +-0.070770042277002398468 0.67434228105399462994 -0.93293408971343372293 +5 0 1 2 3 4 +5 5 6 7 8 9 +4 10 11 12 13 +3 14 15 16 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-4-rnd-polygons-4-6.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-4-rnd-polygons-4-6.off new file mode 100644 index 00000000000..eb5def17d8c --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-4-rnd-polygons-4-6.off @@ -0,0 +1,31 @@ +OFF +25 4 0 +0.42368054211531858133 0.18253980947404854773 0.43361217636176885293 +0.022479024642939653134 0.54906919604958193126 0.18056913227494222896 +0.2811647526241494166 0.52705548769951282573 0.022668645874355360104 +0.56065427807169632146 0.47592798567162025725 -0.10696848363655320213 +0.97118185417342761667 0.3697089496003267417 -0.25076552479989255851 +0.53714992649207637943 0.15247177832828684441 0.39492925062101502665 +0.47254430936410363184 -0.4706882612609787353 -0.2428207513377572957 +0.072755785530830729968 -0.01774935447864991328 -0.65160096675580014836 +-0.13624087681667856886 -0.19828919510256182157 -1 +0.050171309138895309188 -1 -1 +0.42195670307475763305 -1 -0.48389499638253974378 +0.49191328462142458466 -0.78271514577943301916 -0.31664816804310136344 +0.49305113818899937161 -0.56550106370623254293 -0.24495695687290242049 +-1 0.038516275072130623514 0.26001089527408571822 +-0.0052646635725682039419 0.32175247304120269121 -1 +0.79946300115531654384 1 -1 +-0.24605339821785221499 1 1 +-0.9554579135068776985 0.40209355388461098801 1 +-1 0.32023017788244112491 0.89940428108662362483 +0.71260765954572424796 -1 0.060430338155497906327 +0.93155151560319460202 -0.69967629334922809559 0.098656503647987087158 +1 -0.4563157020167216138 0.27001739515231759636 +1 0.14422055985065576622 0.91048995874330840294 +0.94048661719673254389 0.15625792052012871247 1 +-0.016691632221610047671 -1 1 +6 0 1 2 3 4 5 +7 6 7 8 9 10 11 12 +6 13 14 15 16 17 18 +6 19 20 21 22 23 24 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-5-rnd-polygons-6-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-5-rnd-polygons-6-4.off new file mode 100644 index 00000000000..ff712f41a9b --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-5-rnd-polygons-6-4.off @@ -0,0 +1,35 @@ +OFF +27 6 0 +-0.2715068047190071221 -1 0.46412962243910121929 +-0.41556131280365216085 -0.90858104891710089746 0.47288878458487437761 +-1 -0.56936741358262055179 0.59419955751447206538 +-1 -0.61387797128801713242 0.71471622771556131415 +-0.90099425241208008774 -0.69926309781853057679 0.76976536617697255416 +-0.29447191162235697437 -1 0.50498644571582240737 +-0.030223003459361671985 0.93648592061020163868 -0.25538808561977122125 +-1 -0.45933549239696969124 -0.58688014238550745283 +-1.000000000000000222 -0.84999705118920521052 -0.48244228328099503234 +-0.60402528215280792967 -0.86182664765196137502 -0.19156242825510105821 +0.12970660259586164198 0.12088439022696582936 0.078857202707189461011 +-1 -0.72177693819045085633 0.83216023246343229225 +-1 0.37406387081010966655 -0.092917454358323159358 +-0.98830036813392352357 0.37858296593530049723 -0.10305463361609301653 +-0.18040657510762059257 -0.1191207117686290673 -0.11947976487027342496 +1.000000000000000222 0.86154027175672509564 -1 +-1.000000000000000222 0.018265117785725565325 -1 +-1.000000000000000222 -0.0348121512996918403 -0.89988775377118890297 +1.000000000000000222 0.82949432233434250428 -0.93955619732344142214 +-1.000000000000000222 -0.082875564772366017152 0.066815776847935159921 +-1.000000000000000222 0.68943524446110648896 0.79937834675906738191 +-0.92249289721963756428 0.68021142991910932274 0.82324786639186131598 +0.85219953067226206223 0.079155630539235841137 1 +0.92660760368670014309 0.046142138418764203078 1.000000000000000222 +1 -0.97002886795475151693 0.64666040400679991595 +0.90690715466497651143 -0.91866190284087911877 0.58568732077358443 +1 -0.90095494125933395235 0.7325866581909199482 +6 0 1 2 3 4 5 +5 6 7 8 9 10 +4 11 12 13 14 +4 15 16 17 18 +5 19 20 21 22 23 +3 24 25 26 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-6-rnd-polygons-5-6.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-6-rnd-polygons-5-6.off new file mode 100644 index 00000000000..16b31a2a418 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-6-rnd-polygons-5-6.off @@ -0,0 +1,36 @@ +OFF +29 5 0 +-0.48178769741611227051 1 -0.40226498008333194667 +-0.99999999999999988898 1 -0.071142203066501111253 +-1 0.3202044376978767648 -0.19399362821080207153 +-0.85619431511426502546 0.030494899569326661126 -0.338237114418197371 +-0.43850596395966773278 0.77216215081797490161 -0.47109520884280975395 +-0.16249617378325706407 1 0.95474340241745148106 +-0.61202363503209711304 1 0.60566290196280014868 +-0.92657096327606014441 0.62641184997423038361 0.44387202219214505483 +-1 0.43788565348583619041 0.42846848998027847744 +-1 -1 0.74588647887255832281 +-0.67276600705956091097 -1 1 +-0.17280399373259125451 0.75873005567961882001 1.000000000000000222 +-0.64422541240424657794 -0.66208869775433076832 -0.29821047645336284937 +-0.59456966218893025911 -0.36803138269257229531 -0.67055591044345685958 +-0.54382829504566188028 0.1255921774196187557 -0.057032511143163974743 +-0.59693533282280908381 -0.19911517928313759995 0.28863602078393235661 +-0.61639736649399545776 -0.33832592248428150494 0.3112686009164213341 +-0.65879016193766792853 -0.70682980675170536955 0.024641889949227332307 +-0.35471382283751851094 0.0080511430956209037446 -0.10183150402422080916 +-0.1038072092474866398 0.35634333317040245426 -0.92220023996321076609 +-0.077123271979078172889 0.32411799442990824049 -1 +-0.043860335514287696057 -0.42716595138221413741 -1 +-0.21812514808300687008 -0.81943408539143702818 -0.40971389948606290465 +-0.605360797932613659 -0.53672934735529054251 0.74453450427227796382 +-1 -1 0.33100174522932501731 +-1 -0.90546240791917198543 0.1523697196687137656 +-0.54469904316059647442 -0.58027079033808393049 -0.16039081458786491607 +-0.44074433850305105853 -0.79556548045654285062 0.31530033915674315903 +-0.58176600998124683439 -1 0.60813991626544061653 +5 0 1 2 3 4 +7 5 6 7 8 9 10 11 +6 12 13 14 15 16 17 +6 18 19 20 21 22 23 +5 24 25 26 27 28 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-7-rnd-polygons-7-6.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-7-rnd-polygons-7-6.off new file mode 100644 index 00000000000..73e9a3ccc7e --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-7-rnd-polygons-7-6.off @@ -0,0 +1,52 @@ +OFF +43 7 0 +0.074412784123378983292 -1 -0.011068772854688636864 +0.026128945722450384881 -0.88239971249947379839 -0.033676802799330468607 +-0.16065969807963353944 -0.36456789669340017301 0.28187827640342522084 +-0.31193078139092128565 0.12698081444984532506 1 +0.089674352036377663611 -0.88051352878655197998 1 +0.10424157542349668515 -1 0.46847457883997672967 +0.64662114265388326295 1 0.11468799561689609068 +0.44436554443927822611 1 0.44915525730992317266 +0.49925796977969594259 0.67543190514871676022 0.14745687565465809277 +0.57201710793255799992 0.69985044026737042167 0.043004712012045670511 +-0.56586555544945582596 0.5738638393521606762 0.08001009689987176321 +-1.000000000000000222 0.19984605167689689642 0.32904898654856684637 +-1.000000000000000222 -0.82175641036844471188 1 +-0.13929563338894457303 -0.83201315913053397466 1 +0.7240618580118485248 -0.19772566114688572281 0.5766662231749617451 +-0.093484329206552252423 0.97264048678497871947 -0.18558883978216600408 +0.83089545937890796345 0.34747800744197177014 1 +0.13375893941515232255 1.000000000000000222 0.466307216783310996 +-0.72667479810294466347 1.000000000000000222 -0.55629568223164993501 +-0.21482553640846879794 -0.75602184112805770333 -0.74141752108914182884 +0.068234000858042015425 -1.000000000000000222 -0.51524783299975107642 +0.72628299585493039103 -1.000000000000000222 0.26682611486604412843 +0.99261247481590775266 -0.077885715354007761801 1 +0.71997921500692863006 0.56329877871550948498 0.10798829832919813743 +0.9848476658376950077 0.53006871916521447474 -0.085780994437144042486 +1 0.5204434601226786139 -0.10120243424003405597 +1 -0.34648748966737041854 -0.58790569163943451336 +0.67892723656729581094 -0.30200516615640948803 -0.35066067137619105765 +-0.092950288684415419138 0.19472406060491309621 0.43852254762275166833 +-0.19515163800709400821 1 -0.35117533381896570699 +-0.018434938747652319935 0.77445111539355171448 -0.033414468952952677827 +0.37317618681274145054 0.56282274309647339905 0.16384221728055403666 +0.60200361209568575838 0.47209015917287033837 0.22118845917648921606 +0.76270647370950528376 0.79747244262124428182 -0.42293680870169442221 +0.41264841599779295001 1 -0.62275267976603565501 +0.4431058242321738172 0.1806684207083927296 1 +0.29433832215273336708 -0.058180294499298929045 0.91086137447683479529 +0.19157261580144382962 -0.41363022562282492078 0.77715232514311849421 +0.28703987740721959021 -0.63141453824575166642 0.69382012452536911962 +0.68653312642625596851 -0.49486721821487589246 0.74198403007739466286 +1 -0.34563474998523568971 0.79571715372652962461 +1 -0.33240909253741213192 0.80072622544877425366 +0.64766740643032616465 0.18547054552520489401 1 +6 0 1 2 3 4 5 +4 6 7 8 9 +6 10 11 12 13 14 15 +7 16 17 18 19 20 21 22 +6 23 24 25 26 27 28 +6 29 30 31 32 33 34 +8 35 36 37 38 39 40 41 42 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-8-rnd-polygons-7-8.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-8-rnd-polygons-7-8.off new file mode 100644 index 00000000000..bc19299191d --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-8-rnd-polygons-7-8.off @@ -0,0 +1,46 @@ +OFF +37 7 0 +0.67707555679531650217 -0.75402922244269543484 -1 +-0.67012530974133988071 -0.40514313807465451855 -1 +-0.637423819963698568 -0.43788730234793959983 -0.73183841911602964814 +0.017891888683906759239 -0.63613218097964885356 -0.4166002181775149138 +0.5402693347484084363 -0.75982686542730570878 -0.54458617778309048596 +0.77712436980348198468 -0.7904675012061181949 -0.88369526449212798536 +0.0016271823840253393269 0.44530376685995687325 0.99999999999999988898 +-0.75490851720513107992 1 1 +0.033633518971931168628 1 0.67301857281295163205 +0.23105084913143134062 0.8031484415490386386 0.70248612198202908807 +0.93104247138926798932 -0.93547070552020150647 1 +-0.4882872277191795396 0.51025553164723014277 1.000000000000000222 +-1 0.63288960444639630332 0.67465324492046518934 +-1 -1 -0.65816502375008434367 +0.90418542241735111453 -1 0.92499976132680306051 +-1 0.5112434438275335058 -0.58835822439184004562 +-0.50790035034295244465 0.19627159162019042205 -0.33658589514344777749 +0.44781281816251905514 -0.21109986937630814685 0.43035185761596472798 +0.94787302034807796591 -0.30048399592970531646 1 +-0.3319221387993733785 1 1 +-1 1 0.076507851648463173766 +0.75040135723208467589 1 -0.45223660153568701059 +-0.16430730230173151707 1.000000000000000222 -1 +0.82498767482749535418 0.089639770974265467474 -1.000000000000000222 +0.93074101453444257892 0.57329331786094250845 -0.62192699883546920248 +0.88870330513111384096 0.71295457712018750485 -0.55621446909767524591 +-0.23030331902423356594 1 0.38307765520059955389 +-0.4141418124178022353 0.93621540287599569474 0.24156343889548481663 +-1 0.77907534712697734669 0.26713694226292405975 +-1 0.84707807544367130781 0.96965942652086001274 +-0.68538195249459565872 0.92354119032952786128 0.87406087798807674538 +-0.36704870292943853061 1 0.76796104985074375993 +1 -0.33302486017392907147 -0.26287039854826865781 +0.52932678937387811491 -0.74521535842563779717 0.089890325949902427638 +0.5205211482451357341 -0.77771554920494212482 0.56089987479517455782 +0.7527128272644127982 -0.60710098063744433183 1 +1 -0.40043274905104941919 1 +6 0 1 2 3 4 5 +4 6 7 8 9 +5 10 11 12 13 14 +6 15 16 17 18 19 20 +5 21 22 23 24 25 +6 26 27 28 29 30 31 +5 32 33 34 35 36 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-9-rnd-polygons-12-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-9-rnd-polygons-12-4.off new file mode 100644 index 00000000000..7cb7f44db41 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-4/test-9-rnd-polygons-12-4.off @@ -0,0 +1,74 @@ +OFF +60 12 0 +-0.52353715192158900571 1 -0.76763131129218398208 +-0.35925045040437153521 0.88220173722644745773 -1 +0.36496166772061544581 0.42421799861962383726 -1 +0.66103869786862845537 0.29596429113957534174 -0.01435204122731400557 +0.64422176698690636343 0.32692711004818897358 0.32534793985141252648 +-0.51295166020175186894 1 -0.65576568605954688174 +0.43676770630692807185 0.028509147359708462977 -1 +0.93991216757907980472 0.43323718191597915261 0.0013864853777738814222 +1 0.3136995427216544563 0.027049198513249973763 +1 -0.66357619113174426406 -0.51975418154034014329 +0.59336379218891099896 -0.40255188788196472061 -1.000000000000000222 +0.24362816197267447849 -0.13144617037105463253 0.16149274779709055228 +0.88550001485947238411 0.1735698136641943834 -0.22089195042107107048 +0.99065485694890953461 0.11134170489268251092 0.39380090396657996266 +0.87853113920383396618 0.04499003414157214803 0.53950501213075563456 +-0.56166482936102046786 -0.22684431465001864137 -0.23531207150064259448 +-0.064896886184163157796 1 -0.94301178550965913949 +0.0020300707700982786874 1 -1 +0.52228446569153019752 -0.90896490003234187149 -1 +0.48959104576092815631 -1 -0.95103591841459600431 +0.086496600291317948805 -1 -0.60780153628085842321 +-0.38587332390491246858 -0.77177908906552095125 1 +-0.62699727690716489104 -0.12142404837009589114 0.547388795856016519 +-0.47496608054438510527 1 -0.29905653908521068196 +-0.3214729803864977975 1 -0.31689700016188310228 +0.35497952260971310512 0.2023746241499190246 0.19395443390805305883 +-0.02819767690120107001 -0.82803134197287975304 1 +-1 0.60392410166762089396 -0.42981382305106102804 +-0.51713404481549263281 0.83447254333726550435 -0.60591484976386933425 +-1.000000000000000222 0.58204942776135037974 0.30047960598064843429 +-0.58846582343170594775 0.99286912151291162321 0.42535370538381656047 +-0.5976741496850425106 0.99999999999999988898 0.4005291303705934558 +-0.97453985537013898544 0.99999999999999988898 -0.53637840582796081357 +-1.000000000000000222 -0.022174375373842439285 -0.32270250124887955856 +-1.000000000000000222 -0.026952397842330277911 -0.32140783535409878091 +-0.55927064559517281062 0.82961881277188986861 0.54216916506459145175 +0.79829868801248893284 1 -0.30071152490094454901 +0.075463720527677552452 1 0.077508656174541043504 +-0.58730558151182221671 0.60112751893507998524 0.72444790502948941402 +0.51700927448533229303 0.016357072450976270495 0.58665487215447909009 +1 0.31641391736573337701 0.10814189204634222508 +1 0.79206580235264612 -0.24978211841271347193 +-1 1 0.10487871268773903133 +-0.015825010874265195426 1 -0.12848286629768801426 +0.06323094488425554105 0.91574755729087442546 -0.1012191273762469701 +-1 0.85105217755282080994 0.18621690279764102627 +-0.62921608749442492492 -0.22181367096698439978 0.81978290855770552525 +-0.073319739333169237083 1 -0.084911735598458437657 +0.61366646214259501502 1 -0.3970641378173670466 +1 0.71687235309671981653 -0.4214951760971948902 +1 -0.24687619787520131975 0.092877002615445375389 +0.55207584271315379709 -0.26783215824133210781 0.30758914995256225744 +-0.8694677453972832204 -0.38374761916858612931 0.58521013521533449264 +-0.79780751419488793452 -0.33773751960433634478 0.57216784853208069173 +-0.92993049585954357106 -0.24787014198793877462 1.000000000000000222 +-0.98928977047328037209 -0.29065644013365532494 1.000000000000000222 +-0.55458427587067127273 -1 -0.56933344264448204619 +-0.97449926747620541079 -0.59519050837585374403 -0.75966034998520748367 +-0.59093706600379536376 -0.85182194679605172105 -0.38293043990121250486 +-0.42773188806920425797 -1 -0.29253785208142735197 +6 0 1 2 3 4 5 +5 6 7 8 9 10 +4 11 12 13 14 +6 15 16 17 18 19 20 +6 21 22 23 24 25 26 +3 27 28 29 +6 30 31 32 33 34 35 +6 36 37 38 39 40 41 +4 42 43 44 45 +6 46 47 48 49 50 51 +4 52 53 54 55 +4 56 57 58 59 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-1-rnd-polygons-15-6.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-1-rnd-polygons-15-6.off new file mode 100644 index 00000000000..8694c00c8dc --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-1-rnd-polygons-15-6.off @@ -0,0 +1,97 @@ +OFF +80 15 0 +0.81559174668234235561 0.68673906836842646406 0.59767002185212403376 +0.26899459216932980476 -0.78492362974951956911 -1 +0.068557862958311149848 -1 -1 +-0.49153088312088144551 -1 0.084790786345813953795 +-0.60951841923378879962 -0.61956004344433934783 1 +0.54768027535049101928 0.62215895620943806321 1 +-1 -0.50904049772135329111 -0.53237773906782437372 +-1 -1 -0.94722402609867861756 +-0.13933649181205626233 -1 -0.81728314866400053607 +-0.048193881030255444897 -0.59115748676673396389 -0.45806280431262680342 +-0.25501002039312503644 -0.49571308607498959509 -0.40863969943181710498 +-0.33239235190521410068 -0.96508409761879221378 -1 +-0.044802173468874613438 0.038313409544888751834 -0.54958294963241560716 +0.1832571306137886491 0.32715211756354423134 -0.27982475151320951312 +0.48276973532380929033 -1 -0.21988466232167247494 +-0.32614768607201266581 -1 -1 +0.065780246897935865102 0.63311629336194052975 0.071170337374687753229 +0.6455111955059689155 1 0.3566846123424272097 +0.76451203639331111184 1 1 +0.27569614008658849258 0.65964505530180728154 1 +0.21795356506974955524 0.64826889430492262711 0.77617001918647909875 +1 0.12439953601754004386 -1 +0.55560021029861328401 1 -1 +0.4562794737326255623 1 -0.22987172802057928567 +0.69009326439281903909 0.41168018069580791796 0.27243234541974614693 +1 -0.073993999497906720597 -0.21923827669876230773 +0.40195928618257281695 0.77240222171920147609 -1 +0.078521597216177532741 1.000000000000000222 -0.95670413680043009386 +-1 1.000000000000000222 -0.47079770048747937583 +-1 -0.39894290972836676801 0.15874842246294390558 +-0.18743344201549022587 -0.72538633406988384245 -0.060432633937403418267 +0.98656762723373536694 0.18712550050720494488 -1 +-0.99999999999999988898 0.20673922363249136458 -0.0046808949569565327931 +-0.99999999999999988898 1 -0.38083453275147727268 +0.0639179123491654122 1 0.078519393773307660789 +0.061658148435544027355 0.98274228232070193201 0.085727103683926206279 +-0.16537787205612577979 -0.35095428246616888757 0.62012378138268231531 +-0.38310004124589414065 0.258508691176769001 -0.030455213317039486753 +-0.90339569364540484031 -0.25138061347431062131 -1 +-1 -0.43914055258330297882 -1 +-1 -0.91638685507567618771 -0.077080179808084903215 +-0.59994988753827349637 -0.29883914459600513513 0.23231336494985463381 +-0.73828071506906001176 -0.45123070149498800685 -0.24280925479531006994 +-1 -0.89098764667555419017 -0.19689251417888298246 +-1 -0.83871964379935137757 0.077478718593683285065 +-0.88076259206669405 -0.61246602335294619834 0.19253526682992627705 +-0.81130191436862186816 -0.48078905166690777406 0.2589040667350852587 +-0.53314618542802716394 -0.080466001435819917154 -0.1418704102812643475 +1 -0.051252577011510674909 0.21047830274627393754 +0.60127142143802581042 -0.44423743549107375106 -1 +0.14496030861826197933 -0.99999999999999988898 -1 +0.2706408149313328515 -1.000000000000000222 1 +1 -0.11167946658794089543 1 +-0.55032215213858393099 0.063301402434536663266 -0.97319356726028005689 +-1 -0.29526028609042404005 -0.85699096597225843386 +-1 -0.50346316107786104332 -0.53025112722233003204 +-0.16070966916417428472 -0.38442610655262188235 0.11629989357137371364 +0.27291103468506627827 -0.073589139676360659781 0.059049633548031429942 +0.14434331305333814033 0.239812554808175038 -0.56044154636834675465 +-0.046837286085446377948 0.39879059731085308993 -0.99976090295683783804 +-1 -0.28634380940221254574 1 +-1 -0.89365776742495173224 0.45812052031395844587 +-0.90192814100564799862 -0.93775414270927848204 0.35685911684358190277 +-0.63528180903834841065 -1 0.13297684447445354272 +1 -1 -0.89943303085569703548 +1 0.1896169395109667255 0.16200973641850327511 +-0.11551085539790165169 0.33949517020060371308 1 +0.18055566512784571032 -0.068422936482614438169 0.016258225642593906318 +0.041676302187716611491 0.082387734200295520415 -0.2843835516246018269 +0.017250977322327852581 0.15440970181508328896 -0.39610266617722811322 +0.22112169413211216207 0.46625617590159795789 -0.64441095434923134633 +0.31758516195390407155 0.35356361458029317291 -0.42531850046373920193 +0.33423124167105255911 -0.024922631533164638085 0.076843170620281231464 +-0.56804465888658528527 -0.63252828718680143005 0.24293237953800478346 +-0.45760803846300240894 -0.43513134024678457035 0.42353321023424206349 +-0.10735495511110468292 0.18802077218228718802 1 +-0.36237171239747961726 -0.59573472372624436399 1 +0.57959721997831992191 -0.89894265778066717587 1 +0.86890948162483505612 -0.99999999999999988898 0.50889108156940354721 +0.62266597531463974136 -0.99999999999999988898 1 +6 0 1 2 3 4 5 +5 6 7 8 9 10 +5 11 12 13 14 15 +5 16 17 18 19 20 +5 21 22 23 24 25 +6 26 27 28 29 30 31 +5 32 33 34 35 36 +5 37 38 39 40 41 +6 42 43 44 45 46 47 +5 48 49 50 51 52 +7 53 54 55 56 57 58 59 +7 60 61 62 63 64 65 66 +6 67 68 69 70 71 72 +4 73 74 75 76 +3 77 78 79 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-2-rnd-polygons-20-4.off b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-2-rnd-polygons-20-4.off new file mode 100644 index 00000000000..f5537e2b736 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-5/test-2-rnd-polygons-20-4.off @@ -0,0 +1,120 @@ +OFF +98 5 0 +0.097643937551586082457 0.11361044631327207877 -0.69613591321464585171 +0.26368608867302711918 0.83042896460468518249 0.78812459046006599905 +0.40514151244412571762 0.92262431876082040549 1.000000000000000222 +0.72334223174980871729 0.89525264896593326203 1 +0.58441729540557330047 0.69592327212337923292 0.57106619565552296791 +0.24636295359598289756 0.017937301241380682049 -1 +0.34780393369702727879 -0.058010524325696075087 -0.81010535254419790974 +0.81596164419385663891 -0.21073685358600402484 -0.35475624113903370116 +0.90560842287338716439 -0.011717803120270403605 -0.75348890981991600846 +0.60160067053393662118 0.064356223620836539023 -1 +-0.19237265248000853801 -0.82913966434141350703 -0.86955038982747057119 +0.1902153752276014298 -0.45160386811044472832 -0.84276474609765616997 +0.39320881464052992449 -0.11273780839314505309 -0.58167814218658353553 +0.044867254858687047325 -0.53452456460454222942 -0.74512735266603780104 +0.97274654465961474248 0.11723915112569599506 -1 +0.63608385678696166554 -0.011240725269150292354 -1 +0.37079005738583253882 -0.075999701199932351292 -0.88170164019228369767 +0.85236248059199404281 0.081350503146874003635 -0.96740303303322683348 +0.48993314878195703965 0.26544408718421153015 -0.62617330065147958074 +0.30292793203019474646 0.33513313528591509582 -0.80239842628163504656 +0.17586242054476391994 0.23837434104101268284 -1 +0.20576158191470894643 0.1750826381683171229 -1 +0.43062660099137173297 0.13797843769309919848 -0.76286968693122036989 +0.61037344479335264857 -0.8663210211801208871 0.59038157783258138345 +-0.71601272106157298758 -0.26346572742143692381 -1 +-1 -0.16003190083265131372 -1 +-1 -0.16461839667712435675 -0.93909203175115152362 +-0.97540218134651546222 -0.20957314281880620732 -0.46107419913511082932 +0.13083727070097300738 -0.69433725494628839581 0.62587682010015144307 +0.4125049595218927001 -1 0.63882350754849037688 +-0.90809443854560467635 0.021736551314206722929 0.4323611724471767559 +-0.21311910935214134488 0.16989934383294777454 -0.0054070975267185850122 +1 -0.48366380339643311181 -0.042819663681431391344 +1 -1 0.36854275633498945197 +-1 0.45267754222543854503 0.28846818777740129702 +-0.54086958771933990597 0.30189889033031469534 0.55285173707692836231 +-0.5879263899066589083 0.32665532949955483621 0.74659011728635971128 +-1 0.4759920351330556576 0.84191171447842427789 +0.59148629741438440988 0.1696010893535218611 -0.48069165705108662934 +0.24385090451544166879 1 -0.44049363376727634911 +0.023254978458208272474 1 -0.24720653409164702885 +-0.62545355157668869328 -0.42466362951606301257 0.77481201588307246908 +0.53595237746699420089 -0.25480776633808865927 -0.29689949365474799237 +-0.036157304944911428102 0.67921555785479503786 -0.61202542189549502538 +-0.23498197774965068341 1 -0.50703671696412833114 +0.048367327919994998475 1 -0.43616601791586306902 +0.83067707151715763914 0.28041549923902275854 -0.58756091678630162356 +0.4025675348550907251 -0.701056376746447385 0.93371502378251636234 +-0.37678574104760870211 -0.9023598339676184299 0.57601576509928298364 +-0.25476697130343184394 -1 0.65894738099342842208 +0.27270652404764267329 -1 0.92944789053415954871 +-0.0886386507564320969 0.58872080557625783293 0.52971181131807199005 +-0.65699519724692501121 0.5425589369639411963 1.000000000000000222 +-0.7549256408421953779 -0.72339039287455730864 1 +-0.61732358821934618653 -0.99999999999999988898 0.86760331094495679594 +-0.18858926326511821214 -0.99999999999999988898 0.51060289640621137064 +0.45161699342178374117 0.27392987839325488864 0.059572308833096575265 +-0.83927319582174775281 0.71126954590971980252 -1 +0.95708018814431627952 -0.99999999999999988898 -1 +0.99999999999999988898 -1 -0.94460475206341021348 +1 -0.9937142866426137422 -0.93608861528353493053 +0.78827015934612409964 0.63700329832953894726 1 +0.71073424007042229622 0.71086674777937708392 1 +0.388318174121220272 -0.58127767594377977023 0.46454448967405181925 +0.28741328351995248935 -0.13044053743394873335 1 +-0.038201688507616404777 -0.51162010295902538015 1 +-0.10366295303233216685 -0.97872467537149643313 0.63252181146964869818 +-0.096681150861200298996 -0.99999999999999988898 0.60480746421672237911 +0.32974298441864624554 -0.99999999999999988898 0.13501293774132430703 +-0.2507576593455647096 1 -0.36750565956240993648 +-0.24416119294581720145 0.99834442296420899954 -0.37781722620965163539 +0.29210499222184749257 0.73811038570812348425 -1 +0.55437170304768401685 0.43393132269290946024 -1 +-0.52998675386666005416 1 0.18952366300583531333 +0.45445098169508180153 -0.70224588675874011212 -0.13829661650685892704 +0.20433555926455154728 0.44509273138192423369 0.74096132759343480423 +0.18858400609551678739 0.5255166869847380795 1 +0.28156134959244227822 0.11211582599627267776 1 +0.30634784474953047351 -0.0037881544329512379689 0.85794690761579617266 +1 0.96194611905582172451 0.61307003612856303398 +0.05505864715739793025 0.94544561540733806915 -0.56095162026019529389 +-0.757142509012350029 0.50993029756642205275 -0.8944363467152982583 +-1 0.26643369924817239536 -0.81251702351968613236 +-1 0.18061940747129728857 -0.67491181551595247345 +1 0.88547960928775393263 0.73568585878562264835 +0.084686669879110484938 0.6269165489262080726 -0.22985687504579901952 +0.1033422215974192232 0.61563350902447677715 -0.33924241554892886619 +0.15481933693316396461 0.54984375671891760895 -0.65607925993802185261 +0.046127604767100614802 0.6436912705703070614 -0.0066026137772179690349 +-0.71706914408180155718 0.31635989405704190158 1 +-1.000000000000000222 0.15323197564397167403 0.89211118460611260605 +-1.000000000000000222 0.14666121073503102235 0.89015018851988014781 +-0.47997639373461398193 0.15012129867604701028 1 +-0.069959836387311513661 -0.43749949867418080895 -1 +-0.31067109550012528274 -0.33128801977889527075 -0.85257935365298864738 +-0.23395714419554691776 0.0049983533392443761645 0.18870200875576487176 +0.33070727113522530027 -0.48020235298051894279 -0.85114260464694413422 +0.35127278033040237881 -0.53562163286739039592 -1 +5 0 1 2 3 4 +5 5 6 7 8 9 +4 10 11 12 13 +4 14 15 16 17 +5 18 19 20 21 22 +6 23 24 25 26 27 28 +5 29 30 31 32 33 +4 34 35 36 37 +5 38 39 40 41 42 +4 43 44 45 46 +4 47 48 49 50 +6 51 52 53 54 55 56 +6 57 58 59 60 61 62 +6 63 64 65 66 67 68 +5 69 70 71 72 73 +5 74 75 76 77 78 +6 79 80 81 82 83 84 +4 85 86 87 88 +4 89 90 91 92 +5 93 94 95 96 97 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-1-rnd-polygons-20-6.ply b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-1-rnd-polygons-20-6.ply new file mode 100644 index 00000000000..f8421bd0b62 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-1-rnd-polygons-20-6.ply @@ -0,0 +1,150 @@ +ply +format ascii 1.0 +element vertex 117 +property double x +property double y +property double z +element face 20 +property list uchar int vertex_indices +property uchar red +property uchar green +property uchar blue +property uchar alpha +end_header +0.62538078888644510478 -1 -1 +-0.048008830677860520053 -0.3050525331338432844 -1 +-0.62112434030694030351 0.24378725950733243222 -0.92852162618451772325 +-0.68805956594387440717 -0.19348103652724121804 -0.079391353933158548273 +-0.55412486606260147326 -0.97535728826445211581 1 +-0.5302465917011391916 -1 1 +0.26828125755919784989 -0.91046915783956383628 0.58771894318856165995 +-0.68651149272570077819 -0.17211321889565711629 -0.43656247714954254935 +-0.93159394830511799146 0.50707965625516415731 -1 +-0.45911923352389416575 0.96759078454118041535 -1 +-0.21089676997789097435 0.97060382619221452494 -0.85336750392973659274 +0.89293737389306815366 0.64472308374931430741 0.0069232473640606917442 +1 0.50408841022581385438 0.15727623727788236918 +1 -0.043385520973015290203 0.49327185873017975748 +-0.021681094326524957827 1 -0.80596163614904747785 +0.068270763937482131789 0.88088338836638802043 -1 +-0.066366240479461685586 0.61286829633013217844 -1 +-0.10077559582957332229 1 -0.70350235446631881331 +0.75115147735114451422 -0.1042487144629903606 0.48217996801354084946 +0.9069625806216273789 0.13021842535212102554 0.13356243712218385244 +1.000000000000000222 0.29075094291465042318 0.19062522073031296088 +1 0.33096063028778599513 0.71014028338957091435 +0.94967699755769929837 0.24976077472894403497 0.7520233280068298054 +0.69543106323997649909 -0.17815095961936150415 0.73536449488289890031 +-0.059918184530191744008 -1 0.47801819573748832726 +0.12251703833224071583 -0.84229899929153706495 0.45414078483390613039 +1 -0.71218489241714211246 0.5841590189825267565 +1 -1.000000000000000222 0.69630983871468909996 +1 -0.27532412731080968538 0.0010636087689977783907 +1 1 -0.63474108987366295587 +0.98790878813761218158 1 -0.67145315471401989527 +0.83148036299461514087 0.70632348778026043945 -1 +0.69563927790648372174 -0.12098402037333851056 -1 +0.74467573861058189433 -0.40726515504699223325 -0.70838891675338389042 +0.81210782424913996458 -0.63569123416071438015 -0.38976719888611666143 +0.71162338070864761264 -0.12748496539130133032 -0.045446368095580627622 +0.49000656151645460845 0.59954663559226917258 -0.47881167828596510327 +0.40580874580674741736 0.7191480431888919167 -0.57263406431294072707 +-0.095118047664316168754 0.5290385987903245546 -0.7230752711340533434 +0.29741772872137783867 0.14580077627922638506 -0.36451342059710395427 +0.44433360189554793607 0.030344216964031854589 -0.24296573988378092346 +-0.92576947001015863492 -1 -0.67158959970535736517 +-0.84511955058745125147 -0.60504425680491147332 -1 +1 -0.19969574907482870452 -1 +1 -1 -0.303282733650804881 +0.24099807140790108217 0.59580318881492533301 1 +-0.67120769442925598547 0.50504462555967088999 0.77542374886470621931 +-0.2130809605135417506 0.27863269880837016057 0.15788696786056666266 +0.21239625497403719079 0.16194046534022060735 -0.16435883753100771765 +0.3710959505986978213 0.20019849485364199504 -0.064958839426568965036 +1 0.36719657052464871327 0.37026447904396297961 +1 0.40688533403905341457 0.47683218167873397952 +0.24320652118897184701 0.59582042669127099899 1 +-1 -1 -0.53158168575394082467 +-1 -0.67519174345740262666 -1 +-0.020360059329444155779 -0.22732673652870022396 -1.000000000000000222 +0.0087631252032819902803 -0.37683309801639808256 -0.76519009272734539451 +-0.20176870762085713507 -1 -0.0053024889961983887043 +-1 0.40155047313753688965 1 +-1 0.70250750469883427307 0.33717772492310549293 +-0.60146815117430763031 0.7666915184081481982 -0.0021510364928737854551 +0.26158800749397104202 0.77425356825395486027 -0.44752949395224778106 +1 0.68399528433774881009 -0.61555312951508378561 +1 0.6650266856346653821 -0.57377703383068168197 +0.14810950453498900048 0.31201842003500207534 0.62685931280859485959 +-0.51033440376058392118 0.29110557287580268726 1 +-0.99999999999999988898 -0.17120431330513519175 0.44362122460589753503 +-0.99999999999999988898 -0.99999999999999988898 0.11292937844067617303 +-0.45305259090439908842 -1 0.220406836087417346 +-0.43213061548300246706 -0.27122148048998062642 0.51530280271603357001 +0.8204765983885644598 -0.048585351375921848049 1 +0.69921978384843574972 -0.24946767151919743699 0.73744270842253167864 +0.61239665657392927667 -0.78937848154795964284 0.16662474132020782536 +0.68802256427662900062 -1 0.0057093767060547168102 +0.89495551156040098473 -1 0.12243360947220538471 +0.93328634535106047565 -0.64962601948967690912 0.48270425309336695285 +0.9295541827604510976 -0.11224267386829517301 1.000000000000000222 +-0.69321618065463885827 -0.027347497164555603644 0.11034496090058573681 +-0.26956157114536760666 0.1438785653319240021 -0.56927416855145285268 +-0.17908141395014182118 0.06230554138138824638 -0.61875900796348171085 +-0.018567724073975444554 -0.36644220237867614065 -0.47655699876494805878 +-0.1873187484338691422 -0.54206606393428358182 -0.1188689490711683644 +-0.54378411375194213306 -0.38958983054235607479 0.21284659722257476266 +-0.0057750661552286482181 0.28751455104294387777 -0.19428695046936783619 +0.41033606938701178146 0.66914351385789405668 -1 +0.7970853944441081973 -1 -1.000000000000000222 +0.0044814652502842555748 -1 0.26573843057229828979 +0.11576303047527028434 0.41733148952676762944 0.057587750449945809827 +-0.19822919354582235751 0.55548784072981982618 -0.23117171284946549936 +-0.31855795943125087 0.7319458869091761688 -0.46849111529973408441 +0.011894414556912546316 0.79990992541473182609 -0.38339322223192229266 +0.29600807393024219927 0.81792470717950027659 -0.26877985744560495274 +0.49174803832281965832 0.65891260805008844414 -0.014026088043973677921 +-1 1 -0.27350100043465369604 +-1 0.20583759336389528816 -0.60748504094428557032 +-0.86022261698960056364 0.3255320556683797828 -0.52677990607044289373 +-0.60989143356161279463 0.57166397249149336623 -0.3688829401119393947 +-0.71193800828285125348 1 -0.21091718969455625077 +-0.22881905742356864475 -0.46619829302489923517 -0.99196168341223256437 +-0.96676209395196543994 0.13766862413227656803 -0.98959046289514240868 +-0.47274242625607304502 0.40207679039484089945 -0.63181098637688437591 +-0.035296657964536161389 0.42532763253581429286 -0.42833681171393978016 +0.99999999999999988898 0.19934540136945086419 -0.097801939473051546781 +0.99999999999999988898 0.022732784555739155019 -0.19271981845600111294 +0.56420693902612373272 -0.81790249600331010882 -0.83476382393286363559 +-0.095193786295538068698 -0.64296975157332914019 -0.80070109852153747987 +-0.0056968776155084943635 -0.47906544856349075889 -0.87157903529557867461 +0.076521649059449581287 -0.44887061237955117043 -0.78735503034470366579 +0.18261181811803048336 -0.41930339860327031642 -0.66702270893911908001 +0.12628317168025504635 -0.61743465429447008663 -0.50459578759705692175 +-0.094494398973179266621 -0.78562950964104838469 -0.62268884099901700147 +0.25548011373890616715 0.46781319310305369275 -0.3890524089797486873 +0.049520415836780191932 1 -0.16727439626315646071 +-1 1 0.54981300259722565293 +-1 0.064497289689608078289 0.40732979937235946899 +-0.8884372048131750077 -0.087120011745806053005 0.3080119356761703564 +0.1512886978197185428 -0.4820007096169158789 -0.46252626020950704522 +6 0 1 2 3 4 5 151 47 171 255 +8 6 7 8 9 10 11 12 13 104 165 85 255 +4 14 15 16 17 57 123 160 255 +6 18 19 20 21 22 23 170 81 74 255 +4 24 25 26 27 122 40 149 255 +7 28 29 30 31 32 33 34 75 158 63 255 +6 35 36 37 38 39 40 188 116 138 255 +4 41 42 43 44 141 74 52 255 +8 45 46 47 48 49 50 51 52 93 32 127 255 +5 53 54 55 56 57 46 150 41 255 +8 58 59 60 61 62 63 64 65 159 108 116 255 +4 66 67 68 69 112 67 190 255 +7 70 71 72 73 74 75 76 64 185 105 255 +6 77 78 79 80 81 82 177 143 179 255 +4 83 84 85 86 130 101 94 255 +6 87 88 89 90 91 92 83 59 168 255 +5 93 94 95 96 97 35 177 83 255 +7 98 99 100 101 102 103 104 148 135 157 255 +6 105 106 107 108 109 110 101 94 71 255 +6 111 112 113 114 115 116 53 52 146 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-2-rnd-polygons-25-4.ply b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-2-rnd-polygons-25-4.ply new file mode 100644 index 00000000000..6a561645bf5 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-2-rnd-polygons-25-4.ply @@ -0,0 +1,155 @@ +ply +format ascii 1.0 +element vertex 117 +property double x +property double y +property double z +element face 25 +property list uchar int vertex_indices +property uchar red +property uchar green +property uchar blue +property uchar alpha +end_header +-0.6492317709099472145 0.91792816155549949997 -0.51732626893022093384 +-1 0.76722113316647844172 0.62712356466808694133 +-1 -0.64386322231390069604 0.30321177247198505267 +-0.87052401622459041342 -0.46254105443126569686 -0.090376307090844987258 +-0.35169696785521897819 0.70213114630269379823 0.02114275573886437512 +-0.78782210972903821133 1 -0.14375138575726664758 +-0.81540246630262891436 0.99999999999999977796 -0.1085365890051015747 +-0.5411552708796627531 0.74783678081223103895 0.1522988599233230933 +-0.33109888810266563386 0.62784047086457483999 0.17485068649727336654 +-0.16471584362075969432 -0.080172330498310601099 0.67677845277850212646 +0.44591106311357664449 -0.45364960025535860932 0.96973331371159066094 +0.51520691600044488112 -0.49996271153876503668 1.000000000000000222 +0.91698588032426342487 -1 1 +0.53796047120766532501 -1 0.64243635819418853927 +-1 -0.016842486986782020941 0.52521385379954355077 +-0.53743616288634588063 0.24962438081452456573 0.87669178481952791948 +-0.72537733796147962906 -0.099784587777209679538 1 +-0.77969725691974933746 -0.16847801453348681955 1 +-1 -0.35000203074473029696 0.89287467626918470831 +0.33757439711251369108 -0.75880247116554011555 -1.000000000000000222 +0.072014825397744439139 -0.36794234909335810091 -1 +-0.060942240371767777973 -0.14370050701649350611 -0.6978890451543255935 +0.15725173706824674413 -0.42999980043500851679 -0.32916127858043564558 +0.29811959633777973533 -0.68252853783275591049 -0.80738553670425272646 +-0.22992320028697199596 0.93168638151668892178 1 +-0.19566622887626466953 1.000000000000000222 0.93853293377818625132 +-0.073294138191916255454 1.000000000000000222 0.47793377148881177607 +0.04416005704767439477 0.48724372899406698245 -0.47060556985633483773 +-0.40362563379188320933 -0.61727553250791888928 0.12388874949527549363 +-0.57359060181786003518 -0.37795640797502616515 1 +-0.14436866058795300161 0.72702169729402255083 -0.72257920335441283566 +-0.37872294609794365794 0.9037030366728677766 -0.17877151097741655894 +-1 0.74828599909777404608 0.83653563879324399633 +-1 0.73531058169462093499 0.82766762366959034658 +-0.27922134509899482202 0.66680881618307574765 -0.52029608558064333046 +0.83548753420717714047 0.67466804343210751149 -0.74242251113834467624 +-0.15592489388000135841 0.27847714437158577194 0.34401217164763620016 +0.26081328891060129305 0.88618548778923589282 0.64849086116383847234 +0.57567830745574621876 0.97672139222755338661 0.24255876759513950169 +0.54410182015599517502 -0.49637763391477435215 0.21766789665001329279 +-0.087528866858300830023 -1.000000000000000222 0.8517897556756853783 +-0.13041709660906361523 -1 1 +0.93371941813470216154 0.19590383610479519816 1 +1.000000000000000222 -0.11338311245161639129 0.36148673879328929726 +0.42176632597040675243 0.081800884664054607232 1 +0.22151963098054278101 -0.38172532953167293002 1 +0.51713461990863240914 -1 0.4577043870386293678 +1 -1 -0.0076398394711159889336 +0.068478752695994363209 -0.20649268396450842777 -0.60084976560817560109 +-0.2157907349927216667 0.49028663577496905956 -0.73158457680322219741 +0.68698107798300633853 0.36619177727048579651 -0.84314692362574739093 +1 -0.082797465151927512883 -0.77945088259527106622 +1 -0.35113615686187604759 -0.71177942453669551526 +0.15844645269231852347 -0.99999999999999977796 -0.29876907805630570358 +-0.50325989907105683763 0.43061223639810369823 0.59961170039982780722 +1 -0.99277449079407209531 0.13614690705032894691 +1 -1 0.12990711652633826767 +-0.0038697562321951158026 -0.2092804820791369369 1 +-0.13466898160848270183 -0.18943295961834066832 0.74661747899225061609 +-0.78091660055402201124 -1 -0.17165992600863044792 +-0.15818069007579349528 -1 1 +0.6805587115233990847 0.2086271508925354734 0.99623921542063520462 +0.87888013547572563233 0.66749985183900140129 0.53443169670698542628 +1 0.62168101270250564205 0.63904769706411379548 +1 0.31729080937067533075 1 +0.68720944869058797622 0.20778408687450627967 1 +0.78380286468472859518 0.12112115207231168024 -0.28695265694925847777 +0.89123107322060024504 0.73905230976413682775 -1.000000000000000222 +0.90176151967189399628 0.76824676717872408815 -1 +1 0.76360831133992357334 -0.38297350898227755511 +1 0.60031896537880080622 -0.019232520870773102406 +0.95524797765942093264 0.25896284577572681318 0.46479121338306816913 +1 0.28215160907218989061 -1 +0.20486057234245597103 1 -1 +-0.31955324795974160423 0.99999999999999988898 1 +0.26375465583623591836 0.47339218055257054063 1 +1 0.21293681086934143631 -0.70760807008003934193 +0.93205441963266344452 0.51312744114172326171 0.17798468863530214623 +0.95306669461659732079 0.73620260836307394037 0.61448304224030481091 +1 0.67760696275286202983 0.53529298969943339692 +1 0.43051997234949623827 0.067546703173053404545 +0.23978421192894477931 1.000000000000000222 -0.056683814713617566849 +-0.14537717489131940507 0.76231398297719898949 0.14954579072591273059 +0.55580507184387273334 0.4982681176938174028 0.28947195695905408863 +0.66111802561863297623 1 -0.089961373568054295302 +1 0.41039611511363649488 0.15700215553257929058 +0.40561314037123596954 0.16428539449352308477 0.36608123624678262642 +-0.87863650634538115192 -0.61317604904607025951 0.9732228013696633262 +0.053094332061920032628 -0.53200067674124418282 0.83813687316315088616 +1 0.25084222193721827932 0.25791300734344468903 +0.82827464602806388783 -0.50877996442381301367 -0.21619278114467774254 +0.51132050733107003992 0.087336350168877696643 -0.86703492239518198392 +0.20815925242309057941 0.17918930408955463518 -0.27491245150032261879 +0.49656446951208527141 -0.22169335713804710908 -0.04211690175293046623 +0.99999999999999988898 -0.54224923537887714797 0.48190793646580520893 +0.99999999999999977796 0.4805694899954512378 0.31241803813949031721 +0.59639183951280461127 0.35444417770189529104 -0.35031356208238123573 +0.98828692508008342266 -0.59235340613925846487 0.47037101967785932555 +-0.1220678586438428137 1 -0.0094625688871973825944 +-0.37481290170503250847 1 -0.26459286050946539959 +-0.82110692726043832401 0.45423850863638548514 -0.59430902624475590024 +-0.74420227403362726459 0.39721806107475071679 -0.50405864510012365898 +-0.14176608275245100588 0.85522782182161405373 0.0026947551752278531279 +0.28264605244110668769 -0.77362953971203884951 -0.27370539420898232219 +-0.13631812824137545803 -0.066754149027186210352 0.66058992382421166667 +0.26309933411807906456 -0.30889706059192378884 0.53511494354878086366 +0.95265660871189505876 -0.94344153389661333797 -0.065238938746861346862 +-1 -0.88923214753906743013 -0.407162952148310886 +-0.47942754440669932414 -0.48542127170889370902 -1 +-0.025260989961111184748 -0.094209931014312020547 -0.99999999999999977796 +-0.32932274143438600156 -0.23638274507190698559 0.59158277029439720884 +-0.89747782714584189989 -0.69792251469887167659 0.96188648570114776426 +-1 -0.79568399890303942446 0.83626966784757938989 +-0.10925296823339344932 -0.81507245317875165469 0.18176785520288296638 +-0.42680345675856207199 -0.82508281526252780225 0.77815432999844746931 +-0.48382806750216583724 -1 0.92216422757102478602 +-0.11594268394601163485 -1 0.23371735159644990709 +4 0 1 2 3 151 47 171 255 +5 4 5 6 7 8 104 165 85 255 +5 9 10 11 12 13 57 123 160 255 +5 14 15 16 17 18 170 81 74 255 +5 19 20 21 22 23 122 40 149 255 +6 24 25 26 27 28 29 75 158 63 255 +5 30 31 32 33 34 188 116 138 255 +4 35 36 37 38 141 74 52 255 +4 39 40 41 42 93 32 127 255 +5 43 44 45 46 47 46 150 41 255 +5 48 49 50 51 52 159 108 116 255 +4 53 54 55 56 112 67 190 255 +4 57 58 59 60 64 185 105 255 +5 61 62 63 64 65 177 143 179 255 +6 66 67 68 69 70 71 130 101 94 255 +5 72 73 74 75 76 83 59 168 255 +4 77 78 79 80 35 177 83 255 +4 81 82 83 84 148 135 157 255 +5 85 86 87 88 89 101 94 71 255 +4 90 91 92 93 53 52 146 255 +4 94 95 96 97 166 170 60 255 +5 98 99 100 101 102 119 128 135 255 +4 103 104 105 106 72 86 49 255 +6 107 108 109 110 111 112 184 44 124 255 +4 113 114 115 116 137 163 38 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-3-rnd-polygons-40-6.ply b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-3-rnd-polygons-40-6.ply new file mode 100644 index 00000000000..9428e07e5c4 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/data/stress-test-6/test-3-rnd-polygons-40-6.ply @@ -0,0 +1,276 @@ +ply +format ascii 1.0 +element vertex 223 +property double x +property double y +property double z +element face 40 +property list uchar int vertex_indices +property uchar red +property uchar green +property uchar blue +property uchar alpha +end_header +0.40335259065787576471 0.35465072547903203626 0.85619646800032411793 +0.56991843963696209308 0.66109826737876153935 0.69781204422228970685 +1 0.96641289687684051035 0.4106241902207500849 +1 0.12614928308943518243 0.62117716781331533404 +0.51501778643630702348 0.15580190861472792418 0.85132298646325743618 +0.59246384925596884408 -0.86301732877544212741 0.25346685159151172151 +0.49132744275756545793 -0.60873348514193792447 0.18399991628239528718 +0.34184532313551546645 -0.33994854768174714854 0.32856220318164253147 +0.38656579635105547954 -0.47039365582093140006 0.40086336184615034561 +0.50959641252523413257 -0.73029478981673756621 0.3712098771016697496 +0.56440581472594875123 -0.82180322969965269309 0.30193467483566327481 +-0.91988226360820857241 -0.70454675407136679866 0.34687841788853013281 +-0.434002323687646685 -0.35845426670843416606 -0.99999999999999988898 +0.38614661426348406703 0.6589590820614085187 -1 +0.61814940337009094407 0.97137908337041267703 -0.87082229608176531244 +0.62955568023460228844 1 -0.79487952621709379031 +0.35384863746451122868 1.000000000000000222 0.99999999999999988898 +-0.91505755274844446934 -0.57410689268766890159 1 +-1.000000000000000222 -0.85130969500876263467 -0.65158846541908754801 +-0.63695654162081205563 -0.51346617963542429131 -1 +-0.46380555615368501687 -0.35566071729958503855 -1 +-0.33525424807615483713 -0.24180668113659098406 -0.83493609061546558703 +-1 -0.8611078859872400848 -0.16214169373906167637 +-0.40568061915871972412 0.060360127140847805172 -0.80624322489599897779 +-0.14485353252283805769 0.82019222922485890415 -0.57491547624080152623 +-0.12033042575322080991 0.89154418835598647775 -0.54653920695953916997 +-0.082843065198171167429 1 -0.45665660190278556385 +-0.082834929732726630958 1 -0.45486215629485121648 +-0.20846878479710923004 0.62950189220302910087 -0.22648066370373487466 +-0.33168677330513973711 0.27141124970808960803 -0.40088574417486355639 +0.56822521160052252842 0.81501276261769273201 1 +-0.1660944742623846615 0.50791335813177473923 1 +-0.32910923782500700607 0.13483865714640633215 0.85357537640428837733 +0.18593601222227362779 0.47237099160649959062 0.91222946238743218839 +0.55308013429445002096 0.75589947757933950712 0.97465331502284846543 +-0.44525853506817025806 -0.020459918163220180976 -0.8713383708670601191 +-0.51173657208075351566 0.021188806081958708183 -1 +-0.9071188425394883792 0.12452989623934783425 -1 +-0.99999999999999988898 0.14045464278415428772 -0.95573205925415516404 +-1 0.14004972116187436315 -0.95358576036342834747 +-0.91645643612356875174 0.033132918478467374146 -0.50261134966028864213 +-0.72299347698213178859 -0.088001686877056992109 -0.12855735465174600307 +-0.4521245726175396884 -0.11000157723780634722 -0.38720798435765502177 +-0.056195914528415415179 0.86505369228053807795 0.13122889166647891401 +0.06204992786921454534 0.98705960278543125597 0.10567335471659045076 +0.073597046751425532207 1 0.10635935931667311882 +0.046313927732982512753 1.000000000000000222 0.19954214526908234384 +0.8902597060699840581 0.56778378352568981136 -0.85348130127477617179 +0.53310926967491178985 0.33653480195417961873 -0.2983938196187665981 +0.45254065531538723022 -0.45998306358639240443 0.51804238839203808897 +1 -0.6622006630565480112 0.1841237441431989863 +1.000000000000000222 0.28817073599636977566 -0.6984053630474199581 +0.51394538154089275395 0.37750884186818189914 -1 +-0.26343014108708007193 0.79944998396576383293 -1 +-0.27683592810515234017 0.82530675810043385709 -0.95568405470938766477 +-0.32938622632013081493 1 -0.60705541093233361671 +0.34810979050293622272 1 0.27001014037635856502 +0.83755886237768839564 0.5629930375539298204 -0.13866390444932244486 +0.074620275563303209432 0.57688589203579332398 -0.41232621663467883266 +0.4792573320582177443 1 -0.41203657720104702733 +-0.18210413498392968856 1 0.72881576375245749055 +-0.68293584465805168282 0.26329069902875462672 0.37691727469776736825 +-1 -0.39324489186552846753 1.000000000000000222 +-1 -1 0.0089128258686877875894 +-0.2455138524389086363 -1 -0.080247471814213905406 +-0.18777933722156039953 -0.9383065625444532154 0.013701257476656829998 +-0.92810448540093448688 -0.38804345152906111194 1.000000000000000222 +-0.52231660057250306473 -0.93507573696436629973 -1 +0.63275294375400892299 0.57187081281844787117 -1 +0.70709311153360421276 1 -0.53534357965971524074 +0.26306327362890757904 0.99999999999999977796 0.27752290894039116642 +-0.15181873780205468183 0.61989378067932188188 0.5036674023649856391 +-0.75546851370851408891 -0.64393602644962388837 -0.16465358820878714385 +-1 -0.19063767166873263337 -0.92487085772318300414 +-1 1.000000000000000222 -0.3390016067277515921 +-0.22195665208509551825 1.000000000000000222 -0.16616973649841632055 +0.45096799029202710996 -0.061291794453426126643 -0.53891144916291755518 +0.32123264575530441345 -0.17087384570762320646 -0.62165173136391949082 +0.97512970373188545548 0.46914159852604236933 0.25799172183461899222 +0.61625520612203565918 -0.11325500582488814971 0.57737685355110057728 +0.41017993481401454625 -0.56963786913299419012 0.85514427758866840001 +0.6554388251476399585 -0.64090410061723945834 1 +1 -0.47802678569431628075 1 +1 0.46701815965483983728 0.26873184729901278267 +0.038965870061853674633 0.010424964782414917683 0.61641234574886316633 +-0.64797567930690203042 0.41208845417198458616 0.17301673176432230683 +-1 0.28433382354151492954 -0.009060216586503461525 +-0.99999999999999988898 -0.030126155593106013902 0.033493229864638048021 +-0.87416657294742017292 -0.11763908587725385724 0.11660002081135381613 +-0.27396850741305756038 -0.49685078059663917438 0.5078312139828006222 +-0.16430122013168638184 -0.40232721110141544951 0.55714889709858927969 +-0.70233211725164357286 1 -0.45218000795412194304 +-0.0029386133370163936007 0.99999999999999988898 0.85584597642563597919 +0.11731729206839412727 0.79605744702823399983 1 +0.13260921814553272569 0.7238285063340523795 1.000000000000000222 +-0.32252226415604345888 0.52888067392409476852 0.071609372431644155443 +-0.69040137489647535052 0.76968436557313646418 -0.52106139207294044358 +0.38002767701747341977 0.43138900056129819705 0.24655721598851931819 +0.8856557416665682414 0.56153017739146660059 -0.49664363765363295222 +1 0.65122118075682933203 -0.50185395349411754395 +0.99999999999999988898 0.91899805080311969263 0.2218370856917318279 +0.27192136279294820689 0.54462242610416866651 0.78668098501979455417 +-0.052918883102508099125 -1 -0.99999999999999988898 +0.40374063566264417613 -0.7905705349674120308 -1 +0.75021164650320093514 -0.6139623910911968796 -0.82923778227686462117 +1 -0.48563018333127838666 -0.69642299112958860885 +1 -0.46011558129284424457 -0.45044154939463809662 +0.84365034467355204395 -0.51941484062169185343 -0.33085168466547293376 +-0.045399777054309309321 -0.96263132009415064427 -0.67298053995043694009 +-0.10578382945149647498 -1 -0.76626346140204359969 +-0.79817271839286452195 0.17331638620254680161 0.81224892918275570786 +-0.897529761503622181 0.037724563001789335193 1 +0.75826413258357305835 -1 1 +1 -1 0.85623978615230644795 +1 -0.73279104310389164834 0.6026844186412849691 +-0.16946049346190428242 0.67596547286987085368 -0.038611155223136531256 +1.000000000000000222 1 -0.038620881314754919311 +0.5467457248110856316 0.99999999999999988898 0.81107739506707754451 +0.61200600850456277069 0.8603856505763685103 1 +0.74143742892902542163 0.75155171003147547282 1 +0.99999999999999977796 0.63255322448189077456 0.7805841899724481614 +0.34685845338585863384 0.11741489789838849278 -1 +0.25315074658013791975 -0.092443657368067200242 -0.67927016778041648948 +0.1845528227724529402 -0.26881334377910964806 -0.41517961221010002415 +0.296324941887204929 -0.20535574120564434319 -0.55700064804615756486 +0.48045028536543765707 -0.069307112295522610435 -0.83122653129684342943 +0.45148861765468178975 0.073772347566137069785 -1 +-1 -1 0.2030297788513293622 +-1 0.71075733849146738308 -1 +-0.93551422444745568896 0.72416572995144012914 -1 +0.063887896606013877543 0.12361676498889509479 -0.43155457606459002307 +0.10611933305745695211 -0.33172071814910658594 -0.10517955128033361356 +-0.73246338708991753919 -0.99999999999999977796 0.2421484365276410089 +0.80962512303784639478 -0.99999999999999988898 -0.66861825831963783706 +0.81528975789481639147 -0.97109100243880375203 -1 +1 -0.70371952084870637023 -1 +1 -0.78543826409481276585 0.3076277234364458435 +0.832011054384178661 -0.99999999999999977796 -0.15010279422231542767 +-0.5027470911967665268 -0.26330558036150730761 -0.74289107465514869766 +-0.41744882566602170559 -0.31437932500205645336 -1 +-0.54028033206581937975 -0.71438742282872991218 -1 +-0.68442058944315253832 -0.30607300378858248724 -0.31376994212946884844 +-0.34346232816495131379 0.99999999999999988898 0.9123837460968182711 +-0.39927034854839660305 0.908518871728932087 0.83520992115525172217 +-0.49878084949126111347 0.20029036948087175496 0.17331074915557354021 +-0.36522223091569183673 0.39540095461339619387 0.33509109918396229322 +-0.12346217835424103115 1.000000000000000222 0.86975571294712517023 +-0.48779409373662674376 0.99999999999999988898 0.46689134027321133047 +-0.52346788868444993348 0.10356403920026663323 0.85781475722624100921 +-0.35612210635364283107 -0.23038289411860493616 1 +0.57076913759730574238 -0.27098304866554667747 1 +0.88199388523002175688 -0.11999682332965910803 0.9283369852361411656 +0.72675960662157057524 0.19620554214529117854 0.79364549242100024262 +-0.21854829716824117347 0.94682174518276196462 0.48490719910485513555 +-0.28882394097371300035 1 0.46309729171051716712 +0.44344625828474426577 -0.14398831629769684448 -0.47654418336745663076 +-0.35083411077964499203 -0.49765732929836015153 0.35611194944230145643 +0.10584097964187735852 -1 0.50782285209472433074 +1 -1 -0.073843090453014126329 +1 -0.23241729707850647402 -0.75959081665541461348 +-0.19105831456432503801 0.9713867617622772288 -0.28841609511758498074 +-0.018597422453814405063 -0.010155537837036061194 0.50042826203273338415 +0.30643006852878595936 -0.55505233794400798963 1 +1 -0.3085213126361965319 1 +1.000000000000000222 0.87313970104958626983 0.10614943908083925017 +0.85195853951394595605 1 -0.029617132879128912903 +-0.11876909624511888808 1 -0.29062327576371982385 +0.0042243042511926984922 1 0.17368993927878789707 +-1.000000000000000222 0.24491422686268671249 0.17503706572644028849 +-1.000000000000000222 0.28273825434222626951 1 +-0.046157682805309532825 1 1 +-0.31581696887735255519 0.70124405074529172488 -0.29528464811322346906 +-0.97245564995658084761 0.63091242657458135312 -1 +-1 0.60075029317246664284 -1 +-1 -1.000000000000000222 0.73893984704891124693 +-0.78054266986726994482 -1 1 +0.58443830742056523952 0.49470719996679723973 1.000000000000000222 +0.57241313793198456139 1 -1 +1 0.27900110382289278199 -1 +1 0.20428686940615053969 -0.078435958244999853806 +0.72317658222446512539 0.66863178877325579741 -0.048389359837225059957 +0.52845768235354473319 1 -0.085791609406627306056 +-1 -1 -0.61125923729330067236 +-1 -0.90191411241696251011 -0.69946665843280109165 +-0.40776912536685722133 -0.33521051637077525776 -0.9271546356815512091 +0.19507710763629912409 0.064929019293542722391 -1 +0.22481932181904823453 0.08067402088236659552 -1 +0.7778846255843219204 -0.1773264452205259023 -0.50468728434296228347 +0.49763804710038272994 -1 0.10171670424623444062 +0.31558257354591884303 -1 -0.23739906129329735318 +0.54494521041349108792 -0.78509372738233285105 0.26115618809051721616 +0.84483670083757778091 -0.51733533887643967653 1 +0.4640711471131199195 -1 1 +-0.71207987878007683591 0.546526468933654197 0.28336659284982834706 +-1.0000000000000004441 0.46617113031515866606 0.16322024770967175078 +-1.000000000000000222 0.34462146066366111663 1 +-0.2391856325344622336 0.60307325664984512414 1 +-0.052179057418737836982 0.89886664014013839541 0.67157225182260604779 +-0.45083161250154579758 0.64231126891470324836 0.80029460911176175664 +-0.22567310192605710695 0.0069186820174461120467 1 +-0.058295580307270680742 -0.040173379326060645877 1 +0.05725149015413953657 0.056499836588563251416 0.95490122043876990432 +0.5826243409547987584 0.54360357164255557194 0.73324565257432139376 +0.31897637396387024111 0.85482091342704369374 0.65049316702206749774 +0.93643579147630318094 -0.55426881967225494208 0.80333222165922268942 +0.99999999999999988898 -0.58982020351591568641 0.82096007763334599705 +1 -0.51933911982904223947 1 +0.75587767324786292455 -0.35615058515502645564 1 +-1 -0.74793194673521257165 0.62326181098192134922 +-0.65930904691709546483 -0.78394511107925235471 0.69446148190094403319 +-0.38586787177264858517 -1 0.73157054495922846371 +-1 -1 0.59627538802631674386 +-0.21953125690376329437 0.99999999999999977796 -0.68919401358048015815 +-1 1 -0.73565358295502170094 +-1 0.81630765700870266954 -1 +-0.32880247241388244062 0.78854329881625684351 -1 +-0.21687052967426612149 0.90197144550371555205 -0.83010572615356337245 +-0.20892432557709700314 0.98830633439510062743 -0.70539062753335146638 +-0.5223008295039224258 -1.000000000000000222 -0.16874630051762132266 +-1 -0.4000468853809336367 -0.045308390539949838782 +-1 -0.093372765022726234019 0.19542237323447514408 +-0.10943526188624341788 -0.42136960681741952861 0.58580738803739207388 +0.42550790897131235413 -1 0.52075016184966660404 +5 0 1 2 3 4 151 47 171 255 +6 5 6 7 8 9 10 104 165 85 255 +7 11 12 13 14 15 16 17 57 123 160 255 +5 18 19 20 21 22 170 81 74 255 +7 23 24 25 26 27 28 29 122 40 149 255 +5 30 31 32 33 34 75 158 63 255 +8 35 36 37 38 39 40 41 42 188 116 138 255 +4 43 44 45 46 141 74 52 255 +5 47 48 49 50 51 93 32 127 255 +6 52 53 54 55 56 57 46 150 41 255 +4 58 59 60 61 159 108 116 255 +5 62 63 64 65 66 112 67 190 255 +6 67 68 69 70 71 72 64 185 105 255 +5 73 74 75 76 77 177 143 179 255 +6 78 79 80 81 82 83 130 101 94 255 +7 84 85 86 87 88 89 90 83 59 168 255 +6 91 92 93 94 95 96 35 177 83 255 +5 97 98 99 100 101 148 135 157 255 +8 102 103 104 105 106 107 108 109 101 94 71 255 +6 110 111 112 113 114 115 53 52 146 255 +5 116 117 118 119 120 166 170 60 255 +6 121 122 123 124 125 126 119 128 135 255 +6 127 128 129 130 131 132 72 86 49 255 +5 133 134 135 136 137 184 44 124 255 +4 138 139 140 141 137 163 38 255 +5 142 143 144 145 146 90 121 113 255 +8 147 148 149 150 151 152 153 154 43 79 187 255 +5 155 156 157 158 159 155 37 102 255 +7 160 161 162 163 164 165 166 108 155 176 255 +4 167 168 169 170 61 113 91 255 +6 171 172 173 174 175 176 174 71 165 255 +5 177 178 179 180 181 126 190 80 255 +7 182 183 184 185 186 187 188 79 148 154 255 +4 189 190 191 192 32 106 69 255 +4 193 194 195 196 144 64 143 255 +7 197 198 199 200 201 202 203 97 182 58 255 +4 204 205 206 207 50 140 132 255 +4 208 209 210 211 163 99 47 255 +6 212 213 214 215 216 217 115 57 121 255 +5 218 219 220 221 222 68 175 36 255 diff --git a/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp b/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp new file mode 100644 index 00000000000..77531de7cc0 --- /dev/null +++ b/Kinetic_space_partition/test/Kinetic_space_partition/kinetic_3d_test_all.cpp @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include + +using SCD = CGAL::Simple_cartesian; +using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; +using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; + +std::size_t different = 0; + +template +bool run_test( + const std::string input_filename, + const std::vector& ks, + const std::vector >& results) { + + using Point_3 = typename Kernel::Point_3; + using KSP = CGAL::Kinetic_space_partition_3; + + std::string filename = input_filename; + std::ifstream input_file_off(filename); + std::ifstream input_file_ply(filename); + std::vector input_vertices; + std::vector< std::vector > input_faces; + + if (CGAL::IO::read_OFF(input_file_off, input_vertices, input_faces)) + input_file_off.close(); + else if (CGAL::IO::read_PLY(input_file_ply, input_vertices, input_faces)) + input_file_ply.close(); + else { + std::cerr << "ERROR: can't read the OFF/PLY file " << filename << "!" << std::endl; + return false; + } + + std::cout << input_filename << std::endl; + + for (std::size_t i = 0; i < ks.size(); i++) { + KSP ksp(CGAL::parameters::verbose(false).debug(false)); + + ksp.insert(input_vertices, input_faces); + + ksp.initialize(); + //std::cout << std::endl << "--INPUT K: " << k << std::endl; + ksp.partition(ks[i]); + + CGAL::Linear_cell_complex_for_combinatorial_map<3, 3, CGAL::Linear_cell_complex_traits<3, Kernel>, typename KSP::Linear_cell_complex_min_items> lcc; + ksp.get_linear_cell_complex(lcc); + + std::vector cells = { 0, 2, 3 }, count; + count = lcc.count_cells(cells); + + std::cout << ksp.number_of_volumes() << std::endl; + + if (results[i][0] != count[0] || results[i][1] != count[2] || results[i][2] != count[3]) { + std::cout << "TEST differs: Partitioning has not expected number of vertices, faces or volumes for k = " << ks[i] << std::endl; + + std::cout << "Expectation:" << std::endl; + std::cout << "v: " << results[i][0] << " f : " << results[i][1] << " v : " << results[i][2] << std::endl; + std::cout << "Result k = " << " vertices : " << count[0] << " faces : " << count[2] << " volumes : " << count[3] << std::endl; + std::cout << input_filename << std::endl; + + different++; + } + else std::cout << "TEST PASSED k = " << ks[i] << " " << input_filename << std::endl; + } + + return true; +} + +template +void run_all_tests() { + different = 0; + std::cout.precision(10); + std::vector< std::vector > all_times; + + std::vector > results(3); + + results[0] = { 40, 52, 11 }; + results[1] = { 48, 70, 16 }; + results[2] = { 54, 84, 20 }; + run_test("data/edge-case-test/test-same-time.off", { 1, 2, 3 }, results); + + // Edge tests. + results[0] = { 18, 20, 4 }; + run_test("data/edge-case-test/test-2-polygons.off", { 1 }, results); + + results[0] = { 22, 25, 5 }; + run_test("data/edge-case-test/test-4-polygons.off", { 1 }, results); + + results[0] = { 22, 25, 5 }; + run_test("data/edge-case-test/test-5-polygons.off", { 1 }, results); + + results[0] = { 39, 49, 10 }; + results[1] = { 49, 73, 17 }; + run_test("data/edge-case-test/test-local-global-1.off", { 1, 2 }, results); + + results[0] = { 39, 49, 10 }; + results[1] = { 51, 77, 18 }; + results[2] = { 54, 84, 20 }; + run_test("data/edge-case-test/test-local-global-2.off", { 1, 2, 3 }, results); + + // Stress tests 0. + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-0/test-1-polygon-a.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-0/test-1-polygon-b.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-0/test-1-polygon-c.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-0/test-1-polygon-d.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + run_test("data/stress-test-0/test-2-polygons-ab.off", { 1 }, results); + results[0] = { 19, 19, 3 }; + results[1] = { 20, 22, 4 }; + run_test("data/stress-test-0/test-2-polygons-ac.off", { 1, 2 }, results); + results[0] = { 19, 19, 3 }; + run_test("data/stress-test-0/test-2-polygons-ad.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + run_test("data/stress-test-0/test-2-polygons-bc.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-0/test-2-polygons-bd.off", { 1, 2 }, results); + results[0] = { 19, 21, 4 }; + run_test("data/stress-test-0/test-2-polygons-cd.off", { 1 }, results); + results[0] = { 26, 29, 5 }; + run_test("data/stress-test-0/test-3-polygons-abc.off", { 1 }, results); + results[0] = { 28, 31, 5 }; + results[1] = { 30, 39, 8 }; + run_test("data/stress-test-0/test-3-polygons-abd.off", { 1, 2 }, results); + results[0] = { 25, 28, 5 }; + results[1] = { 27, 32, 6 }; + run_test("data/stress-test-0/test-3-polygons-acd.off", { 1, 2 }, results); + results[0] = { 25, 28, 5 }; + results[1] = { 26, 31, 6 }; + run_test("data/stress-test-0/test-3-polygons-bcd.off", { 1, 2 }, results); + results[0] = { 34, 42, 8 }; + results[1] = { 38, 52, 11 }; + run_test("data/stress-test-0/test-4-polygons-abcd.off", { 1, 2 }, results); + results[0] = { 50, 68, 14 }; + results[1] = { 56, 82, 18 }; + results[2] = { 67, 109, 26 }; + run_test("data/stress-test-0/test-6-polygons.off", { 1, 2, 3 }, results); + + // Stress tests 1. + + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-1/test-1-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-1/test-2-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-1/test-3-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-1/test-4-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + results[1] = { 20, 22, 4 }; + run_test("data/stress-test-1/test-5-rnd-polygons-2-4.off", { 1, 2 }, results); + results[0] = { 18, 18, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-1/test-6-rnd-polygons-2-4.off", { 1, 2 }, results); + results[0] = { 18, 18, 3 }; + run_test("data/stress-test-1/test-7-rnd-polygons-2-4.off", { 1 }, results); + + // Stress tests 2. + + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-2/test-1-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-2/test-2-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-2/test-3-rnd-polygons-1-4.off", { 1 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-2/test-4-rnd-polygons-1-3.off", { 1 }, results); + results[0] = { 17, 17, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-2/test-5-rnd-polygons-2-4.off", { 1, 2 }, results); + results[0] = { 24, 27, 5 }; + run_test("data/stress-test-2/test-6-rnd-polygons-3-4.off", { 1 }, results); + + // Stress tests 3. + + results[0] = { 18, 18, 3 }; + results[1] = { 20, 22, 4 }; + run_test("data/stress-test-3/test-1-rnd-polygons-2-3.off", { 1, 2 }, results); + results[0] = { 17, 17, 3 }; + run_test("data/stress-test-3/test-2-rnd-polygons-2-3.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-3/test-3-rnd-polygons-2-3.off", { 1, 2 }, results); + results[0] = { 17, 17, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-3/test-4-rnd-polygons-2-4.off", { 1, 2 }, results); + results[0] = { 14, 13, 2 }; + run_test("data/stress-test-3/test-5-rnd-polygons-1-3.off", { 1 }, results); + results[0] = { 18, 18, 3 }; + results[1] = { 19, 21, 4 }; + run_test("data/stress-test-3/test-6-rnd-polygons-2-3.off", { 1, 2 }, results); + results[0] = { 21, 21, 3 }; + results[1] = { 22, 24, 4 }; + run_test("data/stress-test-3/test-7-rnd-polygons-2-4.off", { 1, 2 }, results); + results[0] = { 17, 17, 3 }; + results[1] = { 18, 20, 4 }; + run_test("data/stress-test-3/test-8-rnd-polygons-2-10.off", { 1, 2 }, results); + results[0] = { 31, 37, 7 }; + results[1] = { 34, 46, 10 }; + results[2] = { 39, 57, 13 }; + run_test("data/stress-test-3/test-9-rnd-polygons-4-4.off", { 1, 2, 3 }, results); + results[0] = { 51, 72, 15 }; + run_test("data/stress-test-3/test-10-rnd-polygons-5-4.off", { 1 }, results); + + // Stress tests 4. + + results[0] = { 17, 17, 3 }; + run_test("data/stress-test-4/test-1-rnd-polygons-2-6.off", { 1 }, results); + results[0] = { 27, 32, 6 }; + results[1] = { 29, 38, 8 }; + run_test("data/stress-test-4/test-2-rnd-polygons-3-8.off", { 1, 2 }, results); + results[0] = { 32, 38, 7 }; + results[1] = { 35, 45, 9 }; + results[2] = { 37, 51, 11 }; + run_test("data/stress-test-4/test-3-rnd-polygons-4-4.off", { 1, 2, 3 }, results); + results[0] = { 25, 27, 5 }; + results[1] = { 30, 36, 7 }; + results[2] = { 37, 53, 12 }; + run_test("data/stress-test-4/test-4-rnd-polygons-4-6.off", { 1, 2, 3 }, results); + results[0] = { 61, 91, 20 }; + results[1] = { 73, 121, 29 }; + results[2] = { 83, 145, 36 }; + run_test("data/stress-test-4/test-5-rnd-polygons-6-4.off", { 1, 2, 3 }, results); + + results[0] = { 43, 58, 12 }; + results[1] = { 50, 75, 17 }; + run_test("data/stress-test-4/test-6-rnd-polygons-5-6.off", { 1, 2 }, results); + results[0] = { 63, 94, 21 }; + results[1] = { 84, 141, 34 }; + results[2] = { 90, 157, 39 }; + run_test("data/stress-test-4/test-7-rnd-polygons-7-6.off", { 1, 2, 3 }, results); + results[0] = { 56, 77, 16 }; + results[1] = { 68, 107, 25 }; + results[2] = { 69, 110, 26 }; + run_test("data/stress-test-4/test-8-rnd-polygons-7-8.off", { 1, 2, 3 }, results); + results[0] = { 173, 305, 74 }; + results[1] = { 194, 370, 96 }; + results[2] = { 207, 407, 108 }; + run_test("data/stress-test-4/test-9-rnd-polygons-12-4.off", { 1, 2, 3 }, results); + + // Stress tests 5. + + results[0] = { 185, 308, 71 }; + results[1] = { 223, 406, 101 }; + results[2] = { 277, 548, 145 }; + run_test("data/stress-test-5/test-1-rnd-polygons-15-6.off", { 1, 2, 3 }, results); + + results[0] = { 50, 71, 15 }; + results[1] = { 56, 85, 19 }; + results[2] = { 63, 102, 24 }; + run_test("data/stress-test-5/test-2-rnd-polygons-20-4.off", { 1, 2, 3 }, results); + + // Real data tests. + + results[0] = { 94, 150, 35 }; + results[1] = { 111, 191, 47 }; + results[2] = { 127, 233, 60 }; + run_test("data/real-data-test/test-10-polygons.off", { 1, 2, 3 }, results); + + results[0] = { 206, 385, 99 }; + results[1] = { 237, 462, 122 }; + results[2] = { 260, 529, 144 }; + run_test("data/real-data-test/test-15-polygons.off", { 1, 2, 3 }, results); + + results[0] = { 1156, 2466, 677 }; + results[1] = { 1131, 2387, 650 }; + results[2] = { 1395, 3115, 882 }; + run_test("data/real-data-test/test-40-polygons.ply", { 1, 2, 3 }, results); + + const auto kernel_name = boost::typeindex::type_id().pretty_name(); + if (different != 0) { + std::cout << std::endl << kernel_name << different << " TESTS differ from typical values!" << std::endl << std::endl; + } + std::cout << std::endl << kernel_name << " TESTS SUCCESS!" << std::endl << std::endl; +} + +int main(const int /* argc */, const char** /* argv */) { + run_all_tests(); + run_all_tests(); + //run_all_tests(); + //run_all_tests(); + return EXIT_SUCCESS; +} diff --git a/Kinetic_space_partition/timings.md b/Kinetic_space_partition/timings.md new file mode 100644 index 00000000000..66c0257e24a --- /dev/null +++ b/Kinetic_space_partition/timings.md @@ -0,0 +1,134 @@ +Latest timings in Debug/Release for k = 1, sec.: + +# stress test 0 +test-6-polygons : 0.25661897659301757812 / 0.067038059234619140625 + +# stress test 1 +test-8-rnd-polygons-3-4 : 0.11995100975036621094 / 0.041974067687988281250 + +# stress test 2 +test-6-rnd-polygons-3-4 : 0.09911918640136718750 / 0.033115148544311523438 + +# stress test 3 +test-5-rnd-polygons-1-3 : 1.00860095024108886720 / 0.023632049560546875000 +test-10-rnd-polygons-5-4: 0.38532781600952148438 / 0.081948041915893554688 + +# stress test 4 +test-4-rnd-polygons-4-6 : 0.12927484512329101562 / 0.057893991470336914062 +test-5-rnd-polygons-6-4 : 1.25370502471923828120 / 0.145575046539306640620 +test-6-rnd-polygons-5-6 : 0.22723698616027832031 / 0.079273939132690429688 +test-8-rnd-polygons-7-8 : 0.33871507644653320312 / 0.106122970581054687500 +test-9-rnd-polygons-12-4: 3.80337786674499511720 / 0.498121976852416992190 + +# stress test 5 +test-1-rnd-polygons-15-6: 7.18183803558349609380 / 1.013967990875244140600 +test-2-rnd-polygons-20-4: 39.7726359367370605470 / 2.458597183227539062500 + +# real data +test-10-polygons : 1.63361907005310058590 / 0.273458003997802734380 +test-15-polygons : 4.62825703620910644530 / 0.625633955001831054690 +test-20-polygons : 21.0442938804626464840 / 1.322691202163696289100 + +---------------------------------------- + +Initial timings in Debug/Release for k = 1, sec.: + +# stress test 0 +test-6-polygons : 1.74040412902832031250 / 0.93602585792541503906 // uniform + +# stress test 1 +test-8-rnd-polygons-3-4 : 0.56194806098937988281 / 0.32906508445739746094 // random + +# stress test 2 +test-6-rnd-polygons-3-4 : 0.45945405960083007812 / 0.30190992355346679688 // random + +# stress test 3 +test-5-rnd-polygons-1-3 : 5.19128680229187011720 / 2.26561689376831054690 // long queue +test-10-rnd-polygons-5-4: 1.91159391403198242190 / 0.86900997161865234375 // random + +# stress test 4 +test-4-rnd-polygons-4-6 : 0.65437197685241699219 / 0.40509605407714843750 // random +test-5-rnd-polygons-6-4 : 5.85984015464782714840 / 1.62112498283386230470 // long queue +test-6-rnd-polygons-5-6 : 1.26136302947998046880 / 0.79284501075744628906 // random +test-8-rnd-polygons-7-8 : 1.93336105346679687500 / 1.18615603446960449220 // random +test-9-rnd-polygons-12-4: 20.0204198360443115230 / 10.0104908943176269530 // random + +# stress test 5 +test-1-rnd-polygons-15-6: 33.7394499778747558590 / 19.8511409759521484380 // random +test-2-rnd-polygons-20-4: 146.272709131240844730 / 81.1140849590301513670 // random + +# real data +test-10-polygons : 12.0924539566040039060 / 7.11851215362548828120 // real +test-15-polygons : 23.6766490936279296880 / 14.2001228332519531250 // real +test-20-polygons : 99.7220361232757568360 / 56.3559079170227050780 // real + +---------------------------------------- + +Kinetic Release (Ours) exact(inexact) timings in Release for k = 1, sec.: + +# stress test 0 +test-6-polygons : 0.070086956024169921875(0.0031790733337402343750)/0.0007059574127197265625/0.0011909008026123046875 + +# stress test 1 +test-8-rnd-polygons-3-4 : 0.036616086959838867188(0.0014970302581787109375)/0.0005979537963867187500/0.0005519390106201171875 + +# stress test 2 +test-6-rnd-polygons-3-4 : 0.031713008880615234375(0.0014698505401611328125)/0.0004079341888427734375/0.0003998279571533203125 + +# stress test 3 +test-5-rnd-polygons-1-3 : 0.013506889343261718750(0.0007200241088867187500)/0.0159411430358886718750/0.0001947879791259765625 +test-10-rnd-polygons-5-4: 0.082195997238159179688(0.0027201175689697265625)/0.0013699531555175781250/0.0011131763458251953125 + +# stress test 4 +test-4-rnd-polygons-4-6 : 0.057297945022583007812(0.0021529197692871093750)/0.0004389286041259765625/0.0008690357208251953125 +test-5-rnd-polygons-6-4 : 0.143490076065063476560(0.0038468837738037109375)/0.0038821697235107421875/0.0029499530792236328125 +test-6-rnd-polygons-5-6 : 0.079412937164306640625(0.0025489330291748046875)/0.0006108283996582031250/0.0010251998901367187500 +test-8-rnd-polygons-7-8 : 0.107537984848022460940(0.0038201808929443359375)/0.0009238719940185546875/0.0017449855804443359375 +test-9-rnd-polygons-12-4: 0.496004104614257812500(0.0116169452667236328120)/0.0060429573059082031250/0.0100910663604736328120 + +# stress test 5 +test-1-rnd-polygons-15-6: 0.980010986328125000000(0.0224440097808837890620)/0.0067451000213623046875/0.0224370956420898437500 +test-2-rnd-polygons-20-4: 2.400671005249023437500(0.0474650859832763671880)/0.0210092067718505859380/0.0636138916015625000000 + +# real data +test-10-polygons : 0.270509958267211914060(0.0079689025878906250000)/0.0023949146270751953125/0.0052959918975830078125 +test-15-polygons : 0.587618112564086914060(0.0166199207305908203120)/0.0055429935455322265625/0.0223670005798339843750 +test-20-polygons : 1.292979955673217773400(0.0307259559631347656250)/0.0119550228118896484380/0.0364160537719726562500 + +---------------------------------------- + +Kinetic Release (JPs) timings in Release for k = 1, sec.: + +# stress test 0 +test-6-polygons : 0.0278370000000000006320/0.0347570000000000031700/0.0290839999999999987420 -> 0.093272999999999994802 + +# stress test 1 +test-8-rnd-polygons-3-4 : 0.0131030000000000000640/0.0126979999999999992180/0.0144899999999999994080 -> 0.041284000000000001251 + +# stress test 2 +test-6-rnd-polygons-3-4 : 0.0152639999999999997900/0.0097359999999999998627/0.0176100000000000006530 -> 0.043695999999999998731 + +# stress test 3 +test-5-rnd-polygons-1-3 : 0.0081639999999999993824/0.0024559999999999998499/0.0104040000000000000540 -> 0.021806999999999999995 +test-10-rnd-polygons-5-4: 0.0250879999999999991900/0.0397320000000000034260/0.0229740000000000013650 -> 0.089145000000000002016 + +# stress test 4 +test-4-rnd-polygons-4-6 : 0.0208039999999999995760/0.0158930000000000008760/0.0158310000000000013210 -> 0.053793000000000000538 +test-5-rnd-polygons-6-4 : 0.0386820000000000011050/0.0381319999999999992290/0.0235430000000000014260 -> 0.101880999999999999340 +test-6-rnd-polygons-5-6 : 0.0302249999999999983960/0.0265990000000000011150/0.0220519999999999986860 -> 0.080500000000000002109 +test-8-rnd-polygons-7-8 : 0.0391299999999999981170/0.0386449999999999987970/0.0259939999999999997450 -> 0.105458999999999997190 +test-9-rnd-polygons-12-4: 0.0950430000000000024810/0.1412920000000000009300/0.0490410000000000012580 -> 0.289791000000000020800 + +# stress test 5 +test-1-rnd-polygons-15-6: 0.1477860000000000007000/0.2010520000000000084800/0.0595559999999999978290 -> 0.413885000000000002900 +test-2-rnd-polygons-20-4: 0.2607679999999999997900/0.4968259999999999898500/0.0970730000000000065040 -> 0.864171000000000022470 + +# real data +test-10-polygons : 0.0910910000000000052990/0.1207400000000000001000/0.0345089999999999980100 -> 0.249154999999999987590 +test-15-polygons : 0.1489729999999999943100/0.1405540000000000122600/0.0711249999999999937830 -> 0.366400999999999976710 +test-20-polygons : 0.2263779999999999958900/0.5643979999999999552800/0.1116729999999999944900 -> 0.912132000000000053850 + +# Many polygons: + +50 polygons : 24.09685707092285156250/0.20391988754272460938/4.08338499069213867188 +50 polygons : 16.14023399353027343750/0.12071609497070312500/1.23236894607543945312 diff --git a/Kinetic_space_partition/todo.md b/Kinetic_space_partition/todo.md new file mode 100644 index 00000000000..72100cda68b --- /dev/null +++ b/Kinetic_space_partition/todo.md @@ -0,0 +1,26 @@ +TODO: + +- Try to add a custom exact queue that supports EPECK, because now we convert to doubles there. + +- What about accumulating errors in EPICK? Maybe we could use hybrid mode doing only important computations exactly like intersections e.g. Another idea is to compute intersections with respect to the original input data instead of the data obtained from the previous iteration. + +- Fix case with touching along an edge polygons at the initialization step, they should propagate while now they do not. See e.g. the edge-case-test/test-same-time.off data set. + +- Can we avoid any inexact computations such as sqrt completely? + +- Fix stress-test-6 cases - they are random, their results may depend on an initial unlucky configuration so we probably need to implement random perturbation before running them as in the original paper. + +- Should we also add random perturbation that can be on or off depending on the input. + +- EPICK fails: 40 polygons k = 1 and coplanarity = 0.1 or 40 polygons k = 6 and coplanarity = 0.5; 40 polygons - the one from real-data-test; coplanarity is from Support_plane.h operator==(). + +- EPECK stress-test-5/test-2-rnd-polygons-20-4 runs extremely slow, does it actually finish? Btw real data with the same number of polygons work much faster! Maybe we better test it from now on only on real data because this is what is going to be most-likely used in real life. Can this speed issue be related to conversion from exact to inexact when creating a queue? It seems to hang at the end of each event that is when we check and continue execution with the next event. Maybe the event queue access is so slow? Do we utilize the technique from the paper, storing and accessing only the last three events? The values maybe grow so much that each intersection takes very long time if we use exact type everywhere. + +- Try to avoid errors by using a smaller step. + +- Make intersections a part of kinetic traits that is exact. + +- Try to find out where we lose precision the most. + +- In naive hybrid mode, we manage to succeed for more events, which means that making more exact computations improves the algorithm, that is a good sign, +however doing them all exactly is very slow, so the trade-off must be found. \ No newline at end of file diff --git a/Orthtree/include/CGAL/Orthtree_traits_polygons.h b/Orthtree/include/CGAL/Orthtree_traits_polygons.h new file mode 100644 index 00000000000..12e245ea562 --- /dev/null +++ b/Orthtree/include/CGAL/Orthtree_traits_polygons.h @@ -0,0 +1,197 @@ +// Copyright (c) 2023 INRIA (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Sven Oesau + + +#ifndef CGAL_ORTHREE_TRAITS_POLYGONS_H +#define CGAL_ORTHREE_TRAITS_POLYGONS_H + +#include + +#include +#include +#include + +namespace CGAL +{ + +template +struct Orthtree_traits_polygons : public Orthtree_traits_base +{ + Orthtree_traits_polygons(const std::vector& points, const std::vector >& polygons, typename GeomTraits::FT bbox_dilation = 1.1) + : m_points(points), bbox_dilation(bbox_dilation) { + m_polygons.resize(polygons.size()); + for (std::size_t i = 0;i; + using Tree = Orthtree; + + using Geom_traits = GeomTraits; + using Point_d = typename GeomTraits::Point_3; + using Dimension = Dimension_tag<3>; + using Bbox_d = typename GeomTraits::Iso_cuboid_3; + using FT = typename Geom_traits::FT; + using Sphere_d = typename Geom_traits::Sphere_3; + using Array = std::array; + using Cartesian_const_iterator_d = typename Geom_traits::Cartesian_const_iterator_3; + + using Node_data_element = std::vector; + using Node_data = std::vector >; + + struct Construct_bbox_d { + Bbox_d operator()(const Array& min, + const Array& max) const { + return Bbox_d(min[0], min[1], min[2], max[0], max[1], max[2]); + } + }; + + struct Construct_point_d_from_array { + Point_d operator()(const Array& array) const { + return Point_d(array[0], array[1], array[2]); + } + }; + + Construct_point_d_from_array construct_point_d_from_array_object() const { return Construct_point_d_from_array(); } + Construct_bbox_d construct_bbox_d_object() const { return Construct_bbox_d(); } + + auto construct_root_node_bbox_object() const { + return [&]() -> typename Self::Bbox_d { + Array bbox_min = {(std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)() }, bbox_max = { -(std::numeric_limits::max)(), -(std::numeric_limits::max)(), -(std::numeric_limits::max)() }; + + for (const std::pair &p : m_polygons) { + const Node_data_element& poly = p.second; + for (std::size_t i = 0; i < poly.size(); i++) + for (std::size_t d = 0; d < Dimension::value; d++) { + bbox_min[d] = (std::min)(bbox_min[d], poly[i][d]); + bbox_max[d] = (std::max)(bbox_max[d], poly[i][d]); + } + } + + for (std::size_t d = 0; d < Dimension::value; d++) { + const FT mid = (bbox_min[d] + bbox_max[d]) * 0.5; + const FT side = (bbox_max[d] - mid) * bbox_dilation; + bbox_min[d] = mid - side; + bbox_max[d] = mid + side; + } + + return { construct_point_d_from_array_object()(bbox_min), + construct_point_d_from_array_object()(bbox_max) }; + }; + } + + Point_d interpolate(FT a, FT b, FT l, const Point_d pa, const Point_d pb) const { + FT f = CGAL::abs((a - l) / (a - b)); + assert(f <= 1.0); + return Point_d((1 - f) * pa.x() + f * pb.x(), (1 - f) * pa.y() + f * pb.y(), (1 - f) * pa.z() + f * pb.z()); + } + + void clip_polygons_plane(std::size_t dimension, FT mid, const Node_data& polys, Node_data& lower_polys, Node_data& upper_polys) const { + if (polys.empty()) + return; + + for (const std::pair & p : polys) { + Node_data_element lower, upper; + const Node_data_element& poly = p.second; + + FT last = poly.back()[dimension]; + bool last_lower = (last <= mid); + bool last_upper = (mid <= last); + std::size_t last_index = poly.size() - 1; + + for (std::size_t i = 0; i < poly.size(); i++) { + FT d = poly[i][dimension]; + bool clower = d <= mid; + bool cupper = mid <= d; + + const Point_d& l = poly[last_index]; + const Point_d& c = poly[i]; + + if (last_lower && clower) + lower.push_back(poly[i]); + + if (last_upper && cupper) + upper.push_back(poly[i]); + + // switched sides? + if (last_upper && !cupper) + upper.push_back(interpolate(d, last, mid, c, l)); + + if (last_lower && !clower) + lower.push_back(interpolate(d, last, mid, c, l)); + + if (!last_upper && cupper) { + upper.push_back(interpolate(d, last, mid, c, l)); + upper.push_back(poly[i]); + } + + if (!last_lower && clower) { + lower.push_back(interpolate(d, last, mid, c, l)); + lower.push_back(poly[i]); + } + + last = d; + last_index = i; + last_upper = cupper; + last_lower = clower; + } + if (!upper.empty()) + upper_polys.emplace_back(std::make_pair(p.first, upper)); + + if (!lower.empty()) + lower_polys.emplace_back(std::make_pair(p.first, lower)); + } + } + + template + void distribute_node_contents(NodeIndex n, Tree &tree, const Point_d ¢er) const { + Node_data& ndata = tree.data(n); + + Node_data Xsplits[2]; + Node_data XYsplits[4]; + + clip_polygons_plane(0, center.x(), ndata, Xsplits[0], Xsplits[1]); + + clip_polygons_plane(1, center.y(), Xsplits[0], XYsplits[0], XYsplits[1]); + clip_polygons_plane(1, center.y(), Xsplits[1], XYsplits[2], XYsplits[3]); + + clip_polygons_plane(2, center.z(), XYsplits[0], tree.data(tree.child(n, 0)), tree.data(tree.child(n, 4))); + clip_polygons_plane(2, center.z(), XYsplits[1], tree.data(tree.child(n, 2)), tree.data(tree.child(n, 6))); + clip_polygons_plane(2, center.z(), XYsplits[2], tree.data(tree.child(n, 1)), tree.data(tree.child(n, 5))); + clip_polygons_plane(2, center.z(), XYsplits[3], tree.data(tree.child(n, 3)), tree.data(tree.child(n, 7))); + } + + auto construct_root_node_contents_object() const { + return [&]() -> typename Self::Node_data { + return m_polygons; + }; + } + + auto distribute_node_contents_object() { + return [&](typename Tree::Node_index n, Tree& tree, const typename Self::Point_d& center) { + CGAL_precondition(!tree.is_leaf(n)); + distribute_node_contents(n, tree, center); + }; + } + + Node_data m_polygons; + const std::vector& m_points; + FT bbox_dilation; +}; + +} // end of CGAL namespace + + +#endif // CGAL_ORTHREE_TRAITS_FACE_GRAPH_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/predicates.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/predicates.h index 279d85b9ad6..191a0e2e1b2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/predicates.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/predicates.h @@ -13,7 +13,7 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_PREDICATES_H #define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_PREDICATES_H -#include +#include #include diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 8561d17b88b..7d09a38102b 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -274,6 +274,14 @@ CGAL_add_named_parameter(maximum_running_time_t, maximum_running_time, maximum_r CGAL_add_named_parameter(overlap_t, overlap, overlap) CGAL_add_named_parameter(maximum_normal_deviation_t, maximum_normal_deviation, maximum_normal_deviation) +// kinetic parameters +CGAL_add_named_parameter(bbox_dilation_ratio_t, bbox_dilation_ratio, bbox_dilation_ratio) +CGAL_add_named_parameter(reorient_bbox_t, reorient_bbox, reorient_bbox) +CGAL_add_named_parameter(debug_t, debug, debug) +CGAL_add_named_parameter(angle_tolerance_t, angle_tolerance, angle_tolerance) +CGAL_add_named_parameter(max_octree_depth_t, max_octree_depth, max_octree_depth) +CGAL_add_named_parameter(max_octree_node_size_t, max_octree_node_size, max_octree_node_size) + // List of named parameters used in Shape_detection package CGAL_add_named_parameter(maximum_angle_t, maximum_angle, maximum_angle) CGAL_add_named_parameter(maximum_distance_t, maximum_distance, maximum_distance) diff --git a/Surface_mesh_segmentation/include/CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h b/Surface_mesh_segmentation/include/CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h index 7ef35e755d6..943234810ef 100644 --- a/Surface_mesh_segmentation/include/CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h +++ b/Surface_mesh_segmentation/include/CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h @@ -69,6 +69,19 @@ public: return graph.maxflow(); } + template + void get_labels(VertexLabelMap vertex_label_map, VertexIndexMap vertex_index_map, + const std::vector& inserted_vertices, + InputVertexDescriptorRange& input_range) { + CGAL_assertion(inserted_vertices.size() == input_range.size()); + + for (auto vd : input_range) { + std::size_t index = get(vertex_index_map, vd); + int label = graph.what_segment(inserted_vertices[index]); // Source = 0, Sink = 1 + put(vertex_label_map, vd, label); + } + } + template void update(VertexLabelMap vertex_label_map, const std::vector& inserted_vertices,