mirror of https://github.com/CGAL/cgal
Kinetic Shape Partition (#7198)
PR for Kinetic Partitioning and Reconstruction feature. * Affected package(s): Kinetic Partitioning and Reconstruction * Issue(s) solved (if any): * Feature/Small Feature (if any): [link](https://cgal.geometryfactory.com/CGAL/Members/wiki/Features/Kinetic_Shape_Partition_3) * Link to compiled documentation: [link](https://cgal.github.io/7198/v0/Manual/packages.html#PkgKineticSpacePartition) * License and copyright ownership: GeometryFactory/Inria **TODO:** - [x] check branch size (for @sloriot)
This commit is contained in:
commit
596fa09e20
|
|
@ -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 <typename InputGraph,
|
||||
typename EdgeCostMap,
|
||||
typename VertexLabelCostMap,
|
||||
typename VertexLabelMap,
|
||||
typename NamedParameters>
|
||||
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<InputGraph> GT;
|
||||
typedef typename GT::edge_descriptor input_edge_descriptor;
|
||||
typedef typename GT::vertex_descriptor input_vertex_descriptor;
|
||||
|
||||
typedef typename GetInitializedVertexIndexMap<InputGraph, NamedParameters>::type VertexIndexMap;
|
||||
VertexIndexMap vertex_index_map = CGAL::get_initialized_vertex_index_map(input_graph, np);
|
||||
|
||||
typedef typename GetImplementationTag<NamedParameters>::type Impl_tag;
|
||||
|
||||
// select implementation
|
||||
typedef typename std::conditional
|
||||
<std::is_same<Impl_tag, Alpha_expansion_boost_adjacency_list_tag>::value,
|
||||
Alpha_expansion_boost_adjacency_list_impl,
|
||||
typename std::conditional
|
||||
<std::is_same<Impl_tag, Alpha_expansion_boost_compressed_sparse_row_tag>::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<double>::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<Vertex_descriptor> 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<std::pair<std::size_t, std::s
|
|||
CGAL::parameters::vertex_index_map (graph.vertex_index_map()).
|
||||
implementation_tag (AlphaExpansionImplementationTag()));
|
||||
}
|
||||
|
||||
template <typename AlphaExpansionImplementationTag>
|
||||
double min_cut(const std::vector<std::pair<std::size_t, std::size_t> >& edges,
|
||||
const std::vector<double>& edge_costs,
|
||||
const std::vector<std::vector<double> >& cost_matrix,
|
||||
std::vector<std::size_t>& 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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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 <CGAL/config.h>
|
||||
#include <CGAL/license.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<LCC, CGAL::Kinetic_space_partition_3::Linear_cell_complex_min_items::Face_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;
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -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;
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -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<LCC, CGAL::Kinetic_space_partition_3::Linear_cell_complex_min_items::Volume_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;
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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`
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
BGL
|
||||
Circulator
|
||||
Linear_cell_complex
|
||||
Combinatorial_map
|
||||
Surface_mesh
|
||||
Property_map
|
||||
Polygon_mesh_processing
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*!
|
||||
\example Kinetic_space_partition/kinetic_partition.cpp
|
||||
*/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 315 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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 <string>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSR {
|
||||
|
||||
template<typename FT>
|
||||
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
|
||||
|
|
@ -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 <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSR {
|
||||
|
||||
template<typename FT>
|
||||
class Terminal_parser {
|
||||
|
||||
public:
|
||||
using Input_parameters = std::unordered_map<std::string, std::string>;
|
||||
|
||||
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<std::string> required(1);
|
||||
required[0] = "-data";
|
||||
|
||||
// Set parameters.
|
||||
set_parameters(input_parameters, required);
|
||||
|
||||
// Set here all parameters that should not be saved.
|
||||
std::vector<std::string> 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<typename Scalar>
|
||||
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<Scalar>(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<std::string>(parameters[i]);
|
||||
auto first_letter = str[0];
|
||||
|
||||
if (first_letter == '-') {
|
||||
if (i + 1 < num_parameters) {
|
||||
|
||||
str = static_cast<std::string>(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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Kinetic_space_partition_3.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/IO/polygon_soup_io.h>
|
||||
|
||||
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<Point_3>;
|
||||
using KSP = CGAL::Kinetic_space_partition_3<EPICK>;
|
||||
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<Point_3> input_vertices;
|
||||
std::vector<std::vector<std::size_t> > 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<FT>(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<unsigned int> 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 <CGAL/license/Kinetic_space_partition.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP {
|
||||
namespace internal {
|
||||
|
||||
template<typename FT>
|
||||
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
|
||||
|
|
@ -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 <CGAL/license/Kinetic_space_partition.h>
|
||||
|
||||
// STL includes.
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/centroid.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Iterator_range.h>
|
||||
#include <CGAL/convex_hull_2.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
#include <CGAL/assertions.h>
|
||||
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/linear_least_squares_fitting_2.h>
|
||||
#include <CGAL/linear_least_squares_fitting_3.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_2_algorithms.h>
|
||||
|
||||
// Boost includes.
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
// Convert point to string.
|
||||
template<typename Point_d>
|
||||
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<typename Point_d>
|
||||
decltype(auto) distance(const Point_d& p, const Point_d& q) {
|
||||
using Traits = typename Kernel_traits<Point_d>::Kernel;
|
||||
using FT = typename Traits::FT;
|
||||
const FT sq_dist = CGAL::squared_distance(p, q);
|
||||
return static_cast<FT>(CGAL::approximate_sqrt(sq_dist));
|
||||
}
|
||||
|
||||
// Project 3D point onto 2D plane.
|
||||
template<typename Point_3>
|
||||
typename Kernel_traits<Point_3>::Kernel::Point_2
|
||||
point_2_from_point_3(const Point_3& point_3) {
|
||||
return typename Kernel_traits<Point_3>::Kernel::Point_2(
|
||||
point_3.x(), point_3.y());
|
||||
}
|
||||
|
||||
// Get 3D point from a 2D point.
|
||||
template<typename Point_2>
|
||||
typename Kernel_traits<Point_2>::Kernel::Point_3
|
||||
point_3_from_point_2(const Point_2& point_2) {
|
||||
return typename Kernel_traits<Point_2>::Kernel::Point_3(
|
||||
point_2.x(), point_2.y(), typename Kernel_traits<Point_2>::Kernel::FT(0));
|
||||
}
|
||||
|
||||
// Normalize vector.
|
||||
template<typename Vector_d>
|
||||
inline const Vector_d normalize(const Vector_d& v) {
|
||||
using Traits = typename Kernel_traits<Vector_d>::Kernel;
|
||||
using FT = typename Traits::FT;
|
||||
const FT dot_product = CGAL::abs(v * v);
|
||||
//CGAL_assertion(dot_product != FT(0));
|
||||
return v / static_cast<FT>(CGAL::approximate_sqrt(dot_product));
|
||||
}
|
||||
|
||||
|
||||
// Intersections. Used only in the 2D version.
|
||||
// For the 3D version, see conversions.h!
|
||||
template<typename Type1, typename Type2, typename ResultType>
|
||||
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<typename ResultType, typename Type1, typename Type2>
|
||||
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<typename Point_2, typename Line_2>
|
||||
void boundary_points_on_line_2(
|
||||
const std::vector<Point_2>& input_range,
|
||||
const std::vector<std::size_t>& indices,
|
||||
const Line_2& line, Point_2& p, Point_2& q) {
|
||||
|
||||
using Traits = typename Kernel_traits<Point_2>::Kernel;
|
||||
using FT = typename Traits::FT;
|
||||
using Vector_2 = typename Traits::Vector_2;
|
||||
|
||||
FT min_proj_value = (std::numeric_limits<FT>::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<typename FT>
|
||||
const FT degrees_2(const FT angle_rad) {
|
||||
return angle_rad * FT(180) / static_cast<FT>(CGAL_PI);
|
||||
}
|
||||
|
||||
// Computes an angle in degrees between two directions.
|
||||
template<typename Direction_2>
|
||||
const typename Kernel_traits<Direction_2>::Kernel::FT
|
||||
compute_angle_2(const Direction_2& dir1, const Direction_2& dir2) {
|
||||
|
||||
using Traits = typename Kernel_traits<Direction_2>::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<FT>(
|
||||
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<typename FT>
|
||||
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<typename Direction_2>
|
||||
const typename Kernel_traits<Direction_2>::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<typename IVertex>
|
||||
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<IVertex, std::size_t> 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<std::size_t>;
|
||||
|
||||
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<Kernel, IK>;
|
||||
|
||||
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<Vector_2>& 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<IPoint_2> 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<FT>(fitted_line.a()),
|
||||
static_cast<FT>(fitted_line.b()),
|
||||
static_cast<FT>(fitted_line.c()));
|
||||
return line;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace KSP
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_KSP_UTILS_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 <CGAL/license/Kinetic_space_partition.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/predicates.h>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
#include <CGAL/KSP/debug.h>
|
||||
#include <CGAL/KSP/parameters.h>
|
||||
|
||||
#include <CGAL/KSP_3/Data_structure.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP_3 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits, typename IntersectionKernel>
|
||||
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<IntersectionKernel, Kernel>;
|
||||
using To_exact = CGAL::Cartesian_converter<Kernel, IntersectionKernel>;
|
||||
|
||||
using Data_structure = CGAL::KSP_3::internal::Data_structure<Kernel, IntersectionKernel>;
|
||||
|
||||
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<typename Support_plane::Face_index, typename boost::graph_traits<typename Support_plane::Mesh>::faces_size_type>;
|
||||
using E_constraint_map = typename Mesh::template Property_map<typename Support_plane::Edge_index, bool>;
|
||||
|
||||
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<std::size_t>(-1)),
|
||||
input(static_cast<std::size_t>(-1))
|
||||
{ }
|
||||
};
|
||||
|
||||
using Parameters = KSP::internal::Parameters_3<FT>;
|
||||
|
||||
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<IEdge, std::vector<std::pair<typename Intersection_kernel::Point_3, PFace>>> 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<Tetrahedron_3> 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<Volume_cell>
|
||||
auto& map_volumes = m_data.pface_neighbors();//std::map<PFace, std::pair<int, int>
|
||||
|
||||
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<PFace, std::size_t>& face2index = m_data.face_to_index();
|
||||
std::vector<std::pair<int, int> >& 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<int, int>(-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<int>(volumes[i].pfaces[j].first + 1);
|
||||
volumes[i].neighbors[j] = (pair.first == static_cast<int>(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<Volume_cell>& volumes, std::map<PFace, std::pair<int, int> >& 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<std::size_t>(-1);
|
||||
std::size_t volume_indices[] = { uninitialized, uninitialized };
|
||||
//std::size_t other[] = { static_cast<std::size_t>(-1), static_cast<std::size_t>(-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<int>(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<int>(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<std::pair<PFace, Oriented_side> > queue[2];
|
||||
|
||||
// Get neighbors with smallest dihedral angle
|
||||
const auto pedges = m_data.pedges_of_pface(pface);
|
||||
std::vector<PFace> 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<std::pair<PFace, Oriented_side> >& queue, std::size_t volume_index, std::vector<Volume_cell>& volumes, std::map<PFace, std::pair<int, int> >& 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<PFace> 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<Volume_cell>& volumes, std::map<PFace, std::pair<int, int> >& map_volumes) {
|
||||
auto& pair = map_volumes.at(pface);
|
||||
|
||||
CGAL_assertion(side != COPLANAR);
|
||||
|
||||
if (side == ON_POSITIVE_SIDE) {
|
||||
if (pair.first == static_cast<int>(volume_index))
|
||||
return false;
|
||||
|
||||
pair.first = static_cast<int>(volume_index);
|
||||
volumes[volume_index].add_pface(pface, pair.second);
|
||||
return true;
|
||||
}
|
||||
else if (side == ON_NEGATIVE_SIDE) {
|
||||
if (pair.second == static_cast<int>(volume_index))
|
||||
return false;
|
||||
|
||||
pair.second = static_cast<int>(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<PFace>& 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<std::pair<typename Intersection_kernel::Point_3, PFace> >& 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<typename Intersection_kernel::Point_3, PFace>& p,
|
||||
const std::pair<typename Intersection_kernel::Point_3, PFace>& q) -> bool {
|
||||
if (p.second == pface)
|
||||
return true;
|
||||
if (q.second == pface)
|
||||
return false;
|
||||
return Polygon_mesh_processing::Corefinement::sorted_around_edge<Intersection_kernel>(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<E_constraint_map> 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<typename Support_plane::Edge_index, bool>("e:keep", true).first;
|
||||
F_component_map fcm = mesh.template add_property_map<typename Support_plane::Face_index, typename boost::graph_traits<typename Support_plane::Mesh>::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<bool> initial_component;
|
||||
std::size_t num_components = 0;
|
||||
|
||||
for (const auto& f : mesh.faces())
|
||||
num_components = (std::max<std::size_t>)(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<Halfedge> remove_edges;
|
||||
std::vector<bool> remove_vertices(mesh.vertices().size(), true);
|
||||
std::vector<bool> remove_faces(mesh.faces().size(), true);
|
||||
|
||||
std::vector<bool> 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<Point_3> 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<typename Support_plane::Mesh>::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<Halfedge> 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<std::size_t> 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<int>& ivertex2vertex = m_data.ivertex_to_index();
|
||||
std::vector<Point_3>& vertices = m_data.vertices();
|
||||
std::vector<typename Intersection_kernel::Point_3>& exact_vertices = m_data.exact_vertices();
|
||||
std::vector<std::vector<std::size_t> >& face2vertices = m_data.face_to_vertices();
|
||||
std::vector<std::size_t>& 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<int>(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<bool> coll(m_data.exact_vertices().size(), true);
|
||||
std::unordered_map<std::size_t, std::vector<std::size_t> > 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
|
||||
|
|
@ -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/license/Kinetic_shape_reconstruction.h>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/assertions.h>
|
||||
//#define CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE
|
||||
#include <CGAL/boost/graph/alpha_expansion_graphcut.h>
|
||||
#include <CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
#include <CGAL/KSP/debug.h>
|
||||
#include <CGAL/KSP_3/Data_structure.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSR_3 {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits>
|
||||
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<std::size_t>;
|
||||
|
||||
using Delaunay_2 = CGAL::Delaunay_triangulation_2<Kernel>;
|
||||
using Delaunay_3 = CGAL::Delaunay_triangulation_3<Kernel>;
|
||||
|
||||
Graphcut(
|
||||
const FT lambda) : m_lambda(lambda) { }
|
||||
|
||||
void solve(const std::vector<std::pair<std::size_t, std::size_t> >& edges, const std::vector<FT>& edge_weights, const std::vector<std::vector<double> > &cost_matrix, std::vector<std::size_t> &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<std::size_t, std::size_t> >& edges,
|
||||
const std::vector<FT>& edge_costs,
|
||||
const std::vector< std::vector<double> >& cost_matrix,
|
||||
std::vector<std::size_t>& labels) const {
|
||||
std::vector<std::size_t> tmp = labels;
|
||||
|
||||
std::cout << std::endl << "beta" << m_lambda << std::endl;
|
||||
|
||||
std::vector<FT> edge_costs_lambda(edge_costs.size());
|
||||
std::vector<std::vector<double> > 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<double>)(edge_costs[i], min);
|
||||
max = (std::max<double>)(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<double>)(cost_matrix[0][i], min);
|
||||
min = (std::min<double>)(cost_matrix[1][i], min);
|
||||
max = (std::max<double>)(cost_matrix[0][i], max);
|
||||
max = (std::max<double>)(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<std::size_t>& labels,
|
||||
std::vector<Volume_cell>& 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
|
||||
|
|
@ -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/license/Kinetic_space_partition.h>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
#include <CGAL/Boolean_set_operations_2.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/min_quadrilateral_2.h>
|
||||
#include <CGAL/Aff_transformation_2.h>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
#include <CGAL/KSP/debug.h>
|
||||
#include <CGAL/KSP/parameters.h>
|
||||
|
||||
#include <CGAL/KSP_3/Data_structure.h>
|
||||
|
||||
#include <CGAL/Real_timer.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP_3 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits, typename IntersectionKernel>
|
||||
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<Kernel>;
|
||||
using Direction_2 = typename Kernel::Direction_2;
|
||||
|
||||
using Data_structure = KSP_3::internal::Data_structure<Kernel, Intersection_kernel>;
|
||||
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<Kernel, Intersection_kernel>;
|
||||
using From_exact = CGAL::Cartesian_converter<Intersection_kernel, Kernel>;
|
||||
|
||||
using Bbox_3 = CGAL::Bbox_3;
|
||||
using OBB_traits = CGAL::Oriented_bounding_box_traits_3<Kernel>;
|
||||
|
||||
using Parameters = KSP::internal::Parameters_3<FT>;
|
||||
|
||||
using Timer = CGAL::Real_timer;
|
||||
|
||||
public:
|
||||
Initializer(std::vector<std::vector<Point_3> >& input_polygons, Data_structure& data, const Parameters& parameters) :
|
||||
m_input_polygons(input_polygons), m_data(data), m_parameters(parameters)
|
||||
{ }
|
||||
|
||||
Initializer(std::vector<std::vector<Point_3> >& input_polygons, std::vector<typename Intersection_kernel::Plane_3>& 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<typename Intersection_kernel::Point_3, 8>& bbox, std::vector<std::size_t>& input_polygons) {
|
||||
Timer timer;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
|
||||
std::vector< std::vector<typename Intersection_kernel::Point_3> > 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<std::vector<Point_3> >& m_input_polygons;
|
||||
std::vector<typename Intersection_kernel::Plane_3>& 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<std::size_t>(-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<std::pair<IEdge, Direction_2> > 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<typename Intersection_kernel::Point_2> pts;
|
||||
pts.reserve(face.pts.size());
|
||||
for (auto p : face.pts)
|
||||
pts.push_back(p);
|
||||
|
||||
face.poly = Polygon_2<Intersection_kernel>(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<std::size_t>(-1));
|
||||
|
||||
std::vector<std::pair<IEdge, Direction_2> > 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<std::size_t>(-1), iprev = static_cast<std::size_t>(-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<std::size_t>(-1));
|
||||
CGAL_assertion(iprev != static_cast<std::size_t>(-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<std::size_t, std::vector<IEdge> > 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<typename Intersection_kernel::Segment_2> crossing_polygon_segments;
|
||||
std::vector<IEdge> crossing_iedges;
|
||||
typename Intersection_kernel::FT emin = (std::numeric_limits<double>::max)();
|
||||
typename Intersection_kernel::FT emax = -(std::numeric_limits<double>::max)();
|
||||
FT min_speed = (std::numeric_limits<double>::max)(), max_speed = -(std::numeric_limits<double>::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<IFace, IFace> 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<IFace, IFace> 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<FT, FT>(0, time)); // border barycentric coordinate
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(bary_edge, 0));
|
||||
}
|
||||
else {
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(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<FT, FT>(bary_edge, 0));
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(1, time)); // border barycentric coordinate
|
||||
}
|
||||
else
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(1, 0));
|
||||
}
|
||||
}
|
||||
else if (t < emax && emin < s) {
|
||||
std::pair<IFace, IFace> 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<FT, FT>(0, time)); // border barycentric coordinate
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(bary_edge, 0));
|
||||
}
|
||||
else
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(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<FT, FT>(bary_edge, 0));
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(1, time)); // border barycentric coordinate
|
||||
}
|
||||
else
|
||||
kinetic_interval.push_back(std::pair<FT, FT>(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<typename Intersection_kernel::Point_3, 8>& bbox, std::vector<std::vector<typename Intersection_kernel::Point_3> >& 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<std::vector<typename Intersection_kernel::Point_3> >& bbox_faces, std::vector<std::size_t>& input_polygons) {
|
||||
add_bbox_faces(bbox_faces);
|
||||
|
||||
// Filter input polygons
|
||||
std::vector<bool> 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<typename Intersection_kernel::Point_3> >& 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<Point_2>;
|
||||
using Indices = std::vector<std::size_t>;
|
||||
|
||||
std::map< std::size_t, std::pair<Polygon_2, Indices> > 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<int>(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<typename PointRange>
|
||||
void convert_polygon(const std::size_t support_plane_idx, const PointRange& polygon_3, std::vector<Point_2>& polygon_2) {
|
||||
polygon_2.clear();
|
||||
polygon_2.reserve(polygon_3.size());
|
||||
for (const auto& point : polygon_3) {
|
||||
const Point_3 converted(static_cast<FT>(point.x()), static_cast<FT>(point.y()), static_cast<FT>(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<Point_2>, std::vector<std::size_t> > >& polygons) {
|
||||
std::size_t input_index = 0;
|
||||
std::vector<Point_2> polygon_2;
|
||||
std::vector<std::size_t> 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<Point_2>& polygon_a, std::vector<Point_2>& 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<Point_2> 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<Point_2>& points, std::vector<Point_2>& 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<IFace> 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::set<std::size_t>, std::pair<IVertex, IVertex> >;
|
||||
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::size_t>, std::vector<IVertex> >;
|
||||
std::vector<Pair_pv> 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<IVertex>()));
|
||||
auto& crossed_vertices = todo.back().second;
|
||||
crossed_vertices.push_back(it_a->second.first);
|
||||
|
||||
std::set<std::set<std::size_t>> 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<void(const std::size_t idx)> 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<typename Type1, typename Type2, typename ResultType>
|
||||
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
|
||||
|
|
@ -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 <CGAL/license/Kinetic_space_partition.h>
|
||||
|
||||
// Boost includes.
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP_3 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits, typename IntersectionKernel>
|
||||
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<Intersection_kernel>;
|
||||
|
||||
struct Vertex_property {
|
||||
Point_3 point;
|
||||
Vertex_property() {}
|
||||
Vertex_property(const Point_3& point) : point(point) {}
|
||||
};
|
||||
|
||||
using Kinetic_interval = std::vector<std::pair<IkFT, IkFT> >;
|
||||
|
||||
struct Edge_property {
|
||||
std::size_t line;
|
||||
std::size_t order;
|
||||
std::map<std::size_t, std::pair<std::size_t, std::size_t> > faces; // For each intersecting support plane there is one pair of adjacent faces (or less if the edge is on the bbox)
|
||||
std::set<std::size_t> planes;
|
||||
std::set<std::size_t> crossed;
|
||||
std::map<std::size_t, Kinetic_interval> intervals; // Maps support plane index to the kinetic interval. std::pair<FT, FT> 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<std::size_t, Kinetic_interval>::const_iterator;
|
||||
|
||||
using Graph = boost::adjacency_list<
|
||||
boost::setS, boost::vecS, boost::undirectedS,
|
||||
Vertex_property, Edge_property>;
|
||||
|
||||
using Vertex_descriptor = typename boost::graph_traits<Graph>::vertex_descriptor;
|
||||
using Edge_descriptor = typename boost::graph_traits<Graph>::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<Edge_descriptor, lex>;
|
||||
|
||||
struct Face_property {
|
||||
Face_property() : support_plane(static_cast<std::size_t>(-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<Intersection_kernel> poly;
|
||||
std::vector<Point_2> pts;
|
||||
std::vector<Edge_descriptor> edges;
|
||||
std::vector<Vertex_descriptor> 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<Line_3> m_lines;
|
||||
std::size_t m_nb_lines_on_bbox;
|
||||
std::map<Point_3, Vertex_descriptor> m_map_points;
|
||||
std::map<std::vector<std::size_t>, Vertex_descriptor> m_map_vertices;
|
||||
std::vector<Face_property> m_ifaces;
|
||||
|
||||
std::vector<bool> m_initial_part_of_partition;
|
||||
std::vector<std::map<std::size_t, Kinetic_interval> > m_initial_intervals;
|
||||
std::vector<std::set<std::size_t> > 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<std::size_t>(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<Graph>::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<Vertex_descriptor, bool> 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<Vertex_descriptor, bool> add_vertex(
|
||||
const Point_3& point, const std::vector<std::size_t>& 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<Edge_descriptor, bool> 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<typename IndexContainer>
|
||||
const std::pair<Edge_descriptor, bool> 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<Edge_descriptor, bool> 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<Face_descriptor, Face_descriptor>(-1, -1)));
|
||||
if (pair.first->second.first == static_cast<std::size_t>(-1)) {
|
||||
pair.first->second.first = idx;
|
||||
return true;
|
||||
}
|
||||
else if (pair.first->second.second == static_cast<std::size_t>(-1)) {
|
||||
pair.first->second.second = idx;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void get_faces(std::size_t sp_idx, const Edge_descriptor& edge, std::pair<Face_descriptor, Face_descriptor>& 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<Edge_descriptor, Edge_descriptor>
|
||||
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<Face_descriptor>& faces() {
|
||||
return m_ifaces;
|
||||
}
|
||||
|
||||
const std::vector<Face_descriptor>& 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<std::size_t>& intersected_planes(const Edge_descriptor& edge) const {
|
||||
return m_graph[edge].planes;
|
||||
}
|
||||
|
||||
std::set<std::size_t>& intersected_planes(const Edge_descriptor& edge) {
|
||||
return m_graph[edge].planes;
|
||||
}
|
||||
|
||||
const std::pair<Kinetic_interval_iterator, Kinetic_interval_iterator> kinetic_intervals(const Edge_descriptor& edge) {
|
||||
return std::pair<Kinetic_interval_iterator, Kinetic_interval_iterator>(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<typename GeomTraits, typename IntersectionKernel> std::size_t Intersection_graph<GeomTraits, IntersectionKernel>::Edge_property::edge_counter = 0;
|
||||
|
||||
#endif //DOXYGEN_RUNNING
|
||||
|
||||
} // namespace internal
|
||||
} // namespace KSP_3
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_KSP_3_INTERSECTION_GRAPH_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 <CGAL/license/Kinetic_space_partition.h>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
#include <CGAL/KSP/debug.h>
|
||||
#include <CGAL/KSP/parameters.h>
|
||||
|
||||
#include <CGAL/KSP_3/Data_structure.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP_3 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits, typename IntersectionKernel>
|
||||
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<Kernel, Intersection_kernel>;
|
||||
|
||||
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<FT>;
|
||||
|
||||
using Face_event = typename Data_structure::Support_plane::Face_event;
|
||||
|
||||
using From_exact = CGAL::Cartesian_converter<Intersection_kernel, Kernel>;
|
||||
|
||||
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<int>(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<typename Data_structure::Support_plane::Face_event, std::vector<Face_event>, 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<IEdge> 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
|
||||
|
|
@ -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/license/Kinetic_space_partition.h>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/centroid.h>
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/KSP/utils.h>
|
||||
#include <CGAL/KSP_3/Intersection_graph.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace KSP_3 {
|
||||
namespace internal {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#else
|
||||
|
||||
template<typename GeomTraits, typename IntersectionKernel>
|
||||
class Support_plane {
|
||||
|
||||
public:
|
||||
using Kernel = GeomTraits;
|
||||
using Intersection_kernel = IntersectionKernel;
|
||||
using To_exact = CGAL::Cartesian_converter<Kernel, Intersection_kernel>;
|
||||
using From_exact = CGAL::Cartesian_converter<Intersection_kernel, Kernel>;
|
||||
|
||||
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<Point_2>;
|
||||
using Intersection_graph = CGAL::KSP_3::internal::Intersection_graph<Kernel, Intersection_kernel>;
|
||||
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<Vertex_index, Vector_2>;
|
||||
using V_ivertex_map = typename Mesh::template Property_map<Vertex_index, IVertex>;
|
||||
using V_iedge_map = typename Mesh::template Property_map<Vertex_index, IEdge>;
|
||||
using V_bool_map = typename Mesh::template Property_map<Vertex_index, bool>;
|
||||
using E_iedge_map = typename Mesh::template Property_map<Edge_index, IEdge>;
|
||||
using F_index_map = typename Mesh::template Property_map<Face_index, std::vector<std::size_t> >;
|
||||
using F_uint_map = typename Mesh::template Property_map<Face_index, unsigned int>;
|
||||
using F_bool_map = typename Mesh::template Property_map<Face_index, bool>;
|
||||
using V_original_map = typename Mesh::template Property_map<Vertex_index, bool>;
|
||||
using V_time_map = typename Mesh::template Property_map<Vertex_index, std::vector<FT> >;
|
||||
|
||||
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<Vertex_index, IVertex>("v:ivertex", Intersection_graph::null_ivertex()).first),
|
||||
v_iedge_map(mesh.template add_property_map<Vertex_index, IEdge>("v:iedge", Intersection_graph::null_iedge()).first),
|
||||
e_iedge_map(mesh.template add_property_map<Edge_index, IEdge>("e:iedge", Intersection_graph::null_iedge()).first),
|
||||
input_map(mesh.template add_property_map<Face_index, std::vector<std::size_t> >("f:input", std::vector<std::size_t>()).first),
|
||||
f_initial_map(mesh.template add_property_map<Face_index, bool >("f:initial", false).first),
|
||||
v_original_map(mesh.template add_property_map<Vertex_index, bool>("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<IEdge, std::pair<IFace, IFace> > iedge2ifaces;
|
||||
std::set<IFace> ifaces; // All ifaces in the support plane
|
||||
std::vector<IFace> initial_ifaces; // IFaces which intersect with the input polygon and are thus part of the mesh before the propagation starts.
|
||||
std::vector<Face_index> initial_pfaces;
|
||||
std::map<IVertex, Vertex_index> ivertex2pvertex;
|
||||
IEdge_set unique_iedges;
|
||||
std::set<std::size_t> crossed_lines;
|
||||
|
||||
std::vector<IEdge> iedges;
|
||||
std::vector<Point_2> original_vertices;
|
||||
std::vector<Vector_2> original_vectors;
|
||||
std::vector<Direction_2> original_directions;
|
||||
std::vector<typename Intersection_kernel::Ray_2> 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<Kernel, Intersection_kernel>;
|
||||
|
||||
std::shared_ptr<Data> m_data;
|
||||
|
||||
public:
|
||||
Support_plane() : m_data(std::make_shared<Data>()) {}
|
||||
|
||||
template<typename PointRange>
|
||||
Support_plane(const PointRange& polygon, const bool is_bbox, typename Intersection_kernel::Plane_3 plane) :
|
||||
m_data(std::make_shared<Data>()) {
|
||||
|
||||
std::vector<Point_3> points;
|
||||
points.reserve(polygon.size());
|
||||
for (const auto& point : polygon) {
|
||||
points.push_back(Point_3(
|
||||
static_cast<FT>(point.x()),
|
||||
static_cast<FT>(point.y()),
|
||||
static_cast<FT>(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<std::size_t>(- 1);
|
||||
|
||||
std::vector<Triangle_2> 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<typename Intersection_kernel::Point_3>& polygon, const bool is_bbox) :
|
||||
m_data(std::make_shared<Data>()) {
|
||||
|
||||
From_exact from_exact;
|
||||
|
||||
std::vector<Point_3> 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<std::size_t>(- 1);
|
||||
|
||||
std::vector<Triangle_2> 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<Vertex_index, IVertex>("v:ivertex", Intersection_graph::null_ivertex()).first;
|
||||
m_data->v_iedge_map = m_data->mesh.template add_property_map<Vertex_index, IEdge>("v:iedge", Intersection_graph::null_iedge()).first;
|
||||
m_data->e_iedge_map = m_data->mesh.template add_property_map<Edge_index, IEdge>("e:iedge", Intersection_graph::null_iedge()).first;
|
||||
m_data->input_map = m_data->mesh.template add_property_map<Face_index, std::vector<std::size_t> >("f:input", std::vector<std::size_t>()).first;
|
||||
m_data->v_original_map = m_data->mesh.template add_property_map<Vertex_index, bool>("v:original", false).first;
|
||||
m_data->f_initial_map = m_data->mesh.template add_property_map<Face_index, bool >("f:initial", false).first;
|
||||
}
|
||||
|
||||
void link_property_maps() {
|
||||
m_data->v_ivertex_map = m_data->mesh.template property_map<Vertex_index, IVertex>("v:ivertex").value();
|
||||
m_data->v_iedge_map = m_data->mesh.template property_map<Vertex_index, IEdge>("v:iedge").value();
|
||||
m_data->e_iedge_map = m_data->mesh.template property_map<Edge_index, IEdge>("e:iedge").value();
|
||||
m_data->input_map = m_data->mesh.template property_map<Face_index, std::vector<std::size_t> >("f:input").value();
|
||||
m_data->v_original_map = m_data->mesh.template property_map<Vertex_index, bool>("v:original").value();
|
||||
m_data->f_initial_map = m_data->mesh.template property_map<Face_index, bool >("f:initial").value();
|
||||
}
|
||||
|
||||
void centroid(Point_2& c) {
|
||||
if (m_data->original_vertices.size() < 2)
|
||||
return;
|
||||
std::vector<Triangle_2> 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<IEdge>& 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<IEdge>& 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<Vertex_index, 4>
|
||||
add_bbox_polygon(
|
||||
const std::array<Point_2, 4>& points,
|
||||
const std::array<IVertex, 4>& ivertices) {
|
||||
|
||||
CGAL_assertion(CGAL::is_simple_2(points.begin(), points.end()));
|
||||
CGAL_assertion(CGAL::is_convex_2(points.begin(), points.end()));
|
||||
|
||||
std::array<Vertex_index, 4> 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<typename Pair>
|
||||
std::size_t add_input_polygon(
|
||||
const std::vector<Pair>& points,
|
||||
const std::vector<std::size_t>& 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<Triangle_2> 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<Vertex_index> 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<Vector_2> directions;
|
||||
directions.reserve(n);
|
||||
|
||||
std::vector<std::pair<std::size_t, Direction_2> > 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<FT>(
|
||||
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<std::size_t, Direction_2>(i, directions[i]));
|
||||
|
||||
std::sort(dir_vec.begin(), dir_vec.end(),
|
||||
[&](const std::pair<std::size_t, Direction_2>& a,
|
||||
const std::pair<std::size_t, Direction_2>& 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<std::size_t>(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<typename Pair>
|
||||
bool is_valid_polygon(const std::vector<Pair>& 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<typename Pair>
|
||||
bool is_simple_polygon(const std::vector<Pair>& points) const {
|
||||
std::vector<Point_2> 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<typename Pair>
|
||||
bool is_convex_polygon(const std::vector<Pair>& points) const {
|
||||
std::vector<Point_2> 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<IVertex, Vertex_index>& 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<IEdge, std::pair<IFace, IFace>> neighbor(edge, std::pair<IFace, IFace>(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<Face_index, Face_index> 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<Face_index, Face_index> 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<FT>(CGAL::approximate_sqrt((CGAL::abs(m_data->direction[vi].squared_length()))));
|
||||
}
|
||||
|
||||
const std::vector<std::size_t>& input(const Face_index& fi) const { return m_data->input_map[fi]; }
|
||||
std::vector<std::size_t>& 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<IFace>& 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<IEdge>& iedges() const { return m_data->iedges; }
|
||||
std::vector<IEdge>& 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<typename = typename std::enable_if<identical_kernel>::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<typename = typename std::enable_if<identical_kernel>::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<typename = typename std::enable_if<identical_kernel>::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<typename = typename std::enable_if<identical_kernel>::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<typename GeomTraits, typename IntersectionKernel>
|
||||
bool operator==(const Support_plane<GeomTraits, IntersectionKernel>& a, const Support_plane<GeomTraits, IntersectionKernel>& 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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,2 @@
|
|||
GeometryFactory SARL (France)
|
||||
INRIA Sophia-Antipolis
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Sven Oesau <sven.oesau@geometryfactory.com>
|
||||
|
|
@ -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<Gmpq>`.
|
||||
|
||||
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.
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue