Merge pull request #8186 from lrineau/Triangulation_3-CDT_3-lrineau
New package: CGAL 3D conforming constrained Delaunay triangulations
|
|
@ -1148,3 +1148,27 @@ Polygonal_surface_reconstruction/examples/build*
|
|||
Polygonal_surface_reconstruction/test/build*
|
||||
Solver_interface/examples/build*
|
||||
/Mesh_3/examples/Mesh_3/indicator_0.inr.gz
|
||||
/*.off
|
||||
/*.xyz
|
||||
/r0*
|
||||
all_segments.polylines.txt
|
||||
Data/data/meshes/*.*.edge
|
||||
Data/data/meshes/*.*.ele
|
||||
Data/data/meshes/*.*.face
|
||||
Data/data/meshes/*.*.mesh
|
||||
Data/data/meshes/*.*.node
|
||||
Data/data/meshes/*.*.smesh
|
||||
Data/data/meshes/*.*.vtk
|
||||
Data/data/meshes/*.log
|
||||
Data/data/meshes/*.off-cdt-output.off
|
||||
dump_*.off
|
||||
dump_*.txt
|
||||
dump-*.binary.cgal
|
||||
dump-*.polylines.txt
|
||||
dump-*.xyz
|
||||
dump.off.mesh
|
||||
log.txt
|
||||
patches_after_merge.ply
|
||||
CMakeUserPresets.json
|
||||
/.cache
|
||||
compile_commands.json
|
||||
|
|
|
|||
|
|
@ -302,12 +302,11 @@ public:
|
|||
typename AT::Bounding_box operator()(ConstPrimitiveIterator first,
|
||||
ConstPrimitiveIterator beyond) const
|
||||
{
|
||||
typename AT::Bounding_box bbox = m_traits.compute_bbox(*first,m_traits.bbm);
|
||||
for(++first; first != beyond; ++first)
|
||||
{
|
||||
bbox = bbox + m_traits.compute_bbox(*first,m_traits.bbm);
|
||||
}
|
||||
return bbox;
|
||||
return std::accumulate(first, beyond,
|
||||
typename AT::Bounding_box{} /* empty bbox */,
|
||||
[this](const typename AT::Bounding_box& bbox, const Primitive& pr) {
|
||||
return bbox + m_traits.compute_bbox(pr, m_traits.bbm);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -199,9 +199,7 @@ namespace CGAL {
|
|||
}
|
||||
|
||||
/// returns the axis-aligned bounding box of the whole tree.
|
||||
/// \pre `!empty()`
|
||||
const Bounding_box bbox() const {
|
||||
CGAL_precondition(!empty());
|
||||
if(size() > 1)
|
||||
return root_node()->bbox();
|
||||
else
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ Kml::Nodes Kml::generate_ids_approx(Placemarks& placemarks, const double eps) {
|
|||
|
||||
for (const auto& node : lring->nodes) {
|
||||
// check if there is a node sufficiently close to the current one
|
||||
auto node_index = std::numeric_limits<std::size_t>::max();
|
||||
auto node_index = (std::numeric_limits<std::size_t>::max)();
|
||||
for (std::size_t i = 0; i < nodes.size(); ++i) {
|
||||
const auto dist = node.distance_to(nodes[i]);
|
||||
if (dist < eps) {
|
||||
|
|
@ -278,7 +278,7 @@ Kml::Nodes Kml::generate_ids_approx(Placemarks& placemarks, const double eps) {
|
|||
}
|
||||
}
|
||||
|
||||
if (node_index == std::numeric_limits<std::size_t>::max()) {
|
||||
if (node_index == (std::numeric_limits<std::size_t>::max)()) {
|
||||
// insert new node
|
||||
nodes.push_back(node);
|
||||
const auto node_id = nodes.size() - 1;
|
||||
|
|
@ -301,7 +301,7 @@ Kml::Nodes Kml::generate_ids_approx(Placemarks& placemarks, const double eps) {
|
|||
}
|
||||
|
||||
// find the pair of closest nodes
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_dist = (std::numeric_limits<double>::max)();
|
||||
std::size_t ni1 = 0;
|
||||
std::size_t ni2 = 0;
|
||||
std::size_t num_nodes = nodes.size();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ digraph example {
|
|||
}
|
||||
\enddot
|
||||
|
||||
\cgalHeading{Notations}
|
||||
\cgalHeading{Notations}
|
||||
|
||||
<dl>
|
||||
<dt>`G`</dt> <dd>A type that is a model of a graph concept.</dd>
|
||||
|
|
@ -51,8 +51,8 @@ and adds the requirement for traversal of all vertices in a graph.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%vertex_iterator`</td>
|
||||
|
|
@ -66,9 +66,9 @@ and adds the requirement for traversal of all vertices in a graph.
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`vertices(g)`</td>
|
||||
|
|
@ -92,8 +92,8 @@ and adds the requirement for traversal of all edges in a graph.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%edge_iterator`</td>
|
||||
|
|
@ -107,9 +107,9 @@ and adds the requirement for traversal of all edges in a graph.
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`edges(g)`</td>
|
||||
|
|
@ -143,8 +143,8 @@ and adds the notion of halfedges, where each edge corresponds to two opposite ha
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%halfedge_descriptor`</td>
|
||||
|
|
@ -154,9 +154,9 @@ and adds the notion of halfedges, where each edge corresponds to two opposite ha
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`edge(h, g)`</td>
|
||||
|
|
@ -222,9 +222,9 @@ update the incidence information between vertices and halfedges.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`add_vertex(g)`</td>
|
||||
|
|
@ -272,8 +272,8 @@ and adds the requirements for traversal of all halfedges in the graph.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%halfedge_iterator`</td>
|
||||
|
|
@ -287,9 +287,9 @@ and adds the requirements for traversal of all halfedges in the graph.
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`halfedges(g)`</td>
|
||||
|
|
@ -315,8 +315,8 @@ face.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%face_descriptor`</td>
|
||||
|
|
@ -326,9 +326,9 @@ face.
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`face(h, g)`</td>
|
||||
|
|
@ -361,9 +361,9 @@ the requirement for operations to add faces and to modify face-halfedge relation
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`add_face(g)`</td>
|
||||
|
|
@ -401,8 +401,8 @@ the requirement for traversal of all faces in a graph.
|
|||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<th width="800">Associated Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="associated-type">Associated Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`boost::graph_traits<G>::%face_iterator`</td>
|
||||
|
|
@ -416,9 +416,9 @@ the requirement for traversal of all faces in a graph.
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="392">Valid Expression</th>
|
||||
<th width="392">Return Type</th>
|
||||
<th width="800">Description</th>
|
||||
<th class="valid-expression">Valid Expression</th>
|
||||
<th class="return-type">Return Type</th>
|
||||
<th class="description">Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`faces(g)`</td>
|
||||
|
|
|
|||
|
|
@ -227,6 +227,32 @@ struct GetGeomTraits
|
|||
NamedParametersVPM>::type type;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
// Similar helper for polygon soups
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
struct Polygon_types
|
||||
{
|
||||
typedef typename boost::range_value<PointRange>::type Point_3;
|
||||
typedef typename boost::range_value<PolygonRange>::type Polygon_3;
|
||||
|
||||
typedef typename boost::range_iterator<Polygon_3>::type V_ID_iterator;
|
||||
typedef typename std::iterator_traits<V_ID_iterator>::value_type V_ID;
|
||||
typedef typename std::vector<Polygon_3>::size_type P_ID;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange, typename NamedParameters>
|
||||
struct GetPolygonGeomTraits
|
||||
{
|
||||
typedef typename internal_np::Lookup_named_param_def <
|
||||
internal_np::geom_traits_t,
|
||||
NamedParameters,
|
||||
typename CGAL::Kernel_traits<
|
||||
typename internal::Polygon_types<
|
||||
PointRange, PolygonRange>::Point_3 >::type
|
||||
> ::type type;
|
||||
};
|
||||
|
||||
// Define the following structs:
|
||||
//
|
||||
// GetInitializedVertexIndexMap
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/tags.h>
|
||||
|
|
@ -143,34 +142,29 @@ void duplicate_terminal_vertices(Graph& graph,
|
|||
{
|
||||
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename boost::graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename boost::graph_traits<Graph>::out_edge_iterator out_edge_iterator;
|
||||
|
||||
vertex_iterator b,e;
|
||||
std::tie(b,e) = vertices(graph);
|
||||
std::vector<vertex_descriptor> V(b,e);
|
||||
auto [b, e] = vertices(graph);
|
||||
std::vector<vertex_descriptor> V(b, e); // copy vertices, because the graph may change
|
||||
std::vector<edge_descriptor> out_edges_of_v; // used to store the out edges of a vertex
|
||||
// created here to avoid allocating it in the loop
|
||||
for(vertex_descriptor v : V)
|
||||
{
|
||||
typename boost::graph_traits<OrigGraph>::vertex_descriptor orig_v = graph[v];
|
||||
typename boost::graph_traits<Graph>::degree_size_type deg = degree(v, graph);
|
||||
auto orig_v = graph[v];
|
||||
auto deg = degree(v, graph);
|
||||
if (deg != 2 || is_terminal(orig_v, orig))
|
||||
{
|
||||
auto [b, e] = out_edges(v, graph);
|
||||
out_edges_of_v.assign(b, e); // same as creating a new vector from the range [b,e)
|
||||
for (unsigned int i = 1; i < out_edges_of_v.size(); ++i)
|
||||
{
|
||||
out_edge_iterator b, e;
|
||||
std::tie(b, e) = out_edges(v, graph);
|
||||
std::vector<edge_descriptor> out_edges_of_v(b, e);
|
||||
for (unsigned int i = 1; i < out_edges_of_v.size(); ++i)
|
||||
{
|
||||
edge_descriptor e = out_edges_of_v[i];
|
||||
typename boost::graph_traits<OrigGraph>::edge_descriptor orig_e =
|
||||
graph[e];
|
||||
vertex_descriptor w = target(e, graph);
|
||||
remove_edge(e, graph);
|
||||
vertex_descriptor vc = add_vertex(graph);
|
||||
graph[vc] = orig_v;
|
||||
const std::pair<edge_descriptor, bool> pair = add_edge(vc, w, graph);
|
||||
graph[pair.first] = orig_e;
|
||||
}
|
||||
edge_descriptor e = out_edges_of_v[i];
|
||||
auto orig_e = graph[e];
|
||||
vertex_descriptor w = target(e, graph);
|
||||
remove_edge(e, graph);
|
||||
vertex_descriptor vc = add_vertex(orig_v, graph);
|
||||
add_edge(vc, w, orig_e, graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check all vertices are of degree 1 or 2 and that the source
|
||||
|
|
@ -271,8 +265,7 @@ split_graph_into_polylines(const Graph& graph,
|
|||
V2vmap v2vmap;
|
||||
|
||||
for(Graph_vertex_descriptor v : make_range(vertices(graph))){
|
||||
vertex_descriptor vc = add_vertex(g_copy);
|
||||
g_copy[vc] = v;
|
||||
vertex_descriptor vc = add_vertex(v, g_copy);
|
||||
v2vmap[v] = vc;
|
||||
}
|
||||
|
||||
|
|
@ -281,9 +274,7 @@ split_graph_into_polylines(const Graph& graph,
|
|||
Graph_vertex_descriptor vt = target(e,graph);
|
||||
CGAL_warning_msg(vs != vt, "ignore self loops");
|
||||
if(vs != vt){
|
||||
const std::pair<edge_descriptor, bool> pair =
|
||||
add_edge(v2vmap[vs],v2vmap[vt],g_copy);
|
||||
g_copy[pair.first] = e;
|
||||
add_edge(v2vmap[vs], v2vmap[vt], e, g_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ else()
|
|||
message(STATUS "NOTICE: Tests that use OpenMesh will not be compiled.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0167 NEW)
|
||||
find_package(VTK 9.0 QUIET COMPONENTS CommonCore IOCore IOLegacy IOXML FiltersCore FiltersSources)
|
||||
if (VTK_FOUND AND VTK_LIBRARIES)
|
||||
message(STATUS "VTK ${VTK_VERSION} found ${VTK_LIBRARIES}")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ are of a type that is a model of the concept
|
|||
\cgalRefines{CopyConstructible,Assignable,DefaultConstructible}
|
||||
|
||||
\cgalHasModelsBegin
|
||||
\cgalHasModels{GAL::Polynomial_for_spheres_2_}
|
||||
\cgalHasModels{CGAL::Polynomial_for_spheres_2_}
|
||||
\cgalHasModelsEnd
|
||||
|
||||
\sa `AlgebraicKernelForSpheres`
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@
|
|||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/use.h>
|
||||
#include <CGAL/tags.h>
|
||||
#include <CGAL/type_traits.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
// These are name redefinitions for backwards compatibility
|
||||
// with the pre iterator-traits style adaptors.
|
||||
|
|
@ -640,6 +641,34 @@ operator+( Dist n, const Iterator_from_circulator<C,Ref,Ptr>& circ) {
|
|||
return tmp += n;
|
||||
}
|
||||
|
||||
template <class Circ>
|
||||
class Range_from_circulator {
|
||||
private:
|
||||
Circ anchor;
|
||||
public:
|
||||
using pointer = CGAL::cpp20::remove_cvref_t<decltype(anchor.operator->())>;
|
||||
using const_pointer = CGAL::cpp20::remove_cvref_t<decltype(std::as_const(anchor).operator->())>;
|
||||
using reference = decltype(*anchor);
|
||||
using const_reference = decltype(*std::as_const(anchor));
|
||||
using iterator = Iterator_from_circulator<Circ, reference, pointer>;
|
||||
using const_iterator = Iterator_from_circulator<Circ, const_reference, const_pointer>;
|
||||
|
||||
iterator begin() {
|
||||
return iterator(&anchor, 0);
|
||||
}
|
||||
const_iterator begin() const {
|
||||
return const_iterator(&anchor, 0);
|
||||
}
|
||||
iterator end() {
|
||||
return anchor == nullptr ? iterator(&anchor, 0) : iterator(&anchor, 1);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return anchor == nullptr ? const_iterator(&anchor, 0) : const_iterator(&anchor, 1);
|
||||
}
|
||||
Range_from_circulator() = default;
|
||||
Range_from_circulator(const Circ& c) : anchor(get_min_circulator(c)) {}
|
||||
};
|
||||
|
||||
template < class C >
|
||||
class Container_from_circulator {
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/*!
|
||||
\ingroup PkgConstrainedTriangulation3Concepts
|
||||
\cgalConcept
|
||||
|
||||
The concept `ConformingConstrainedDelaunayTriangulationCellBase_3` refines the concept
|
||||
`TriangulationCellBase_3` and and describes the requirements for a base cell class of
|
||||
the `CGAL::Conforming_constrained_Delaunay_triangulation_3` class.
|
||||
|
||||
\cgalRefines{TriangulationCellBase_3, BaseWithTimeStamp}
|
||||
|
||||
\cgalHasModelsBegin
|
||||
\cgalHasModels{CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3}
|
||||
\cgalHasModelsEnd
|
||||
|
||||
\sa `ConformingConstrainedDelaunayTriangulationVertexBase_3`
|
||||
*/
|
||||
class ConformingConstrainedDelaunayTriangulationCellBase_3 {
|
||||
public:
|
||||
|
||||
/// @name Access Functions
|
||||
///
|
||||
/// The following functions return a reference to an object of type
|
||||
/// `CGAL::Conforming_constrained_Delaunay_triangulation_cell_data_3`, that contains
|
||||
/// the per-cell data required by the implementation of the
|
||||
/// `CGAL::Conforming_constrained_Delaunay_triangulation_3` class.
|
||||
/// @{
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_cell_data_3& ccdt_3_data();
|
||||
const CGAL::Conforming_constrained_Delaunay_triangulation_cell_data_3& ccdt_3_data() const;
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*!
|
||||
\ingroup PkgConstrainedTriangulation3Concepts
|
||||
\cgalConcept
|
||||
|
||||
The concept `ConformingConstrainedDelaunayTriangulationTraits_3` specifies the requirements
|
||||
for the geometric traits class of the triangulation used as the first template
|
||||
parameter `%Triangulation` in the function template
|
||||
`CGAL::make_conforming_constrained_Delaunay_triangulation_3()`.
|
||||
|
||||
\cgalRefines{DelaunayTriangulationTraits_3, ProjectionTraitsGeometricTraits_3}
|
||||
|
||||
\cgalHasModelsBegin
|
||||
\cgalHasModels{CGAL::Exact_predicates_inexact_constructions_kernel (recommended)}
|
||||
\cgalHasModelsBare{All models of the concept `Kernel`}
|
||||
\cgalHasModelsEnd
|
||||
|
||||
*/
|
||||
class ConformingConstrainedDelaunayTriangulationTraits_3 {
|
||||
public:
|
||||
|
||||
/// \name Operations
|
||||
/// The following functions give access to the predicate and construction objects:
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::Angle_3`
|
||||
*/
|
||||
unspecified_type angle_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::CompareAngle_3`
|
||||
*/
|
||||
unspecified_type compare_angle_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ComputeScalarProduct_3`
|
||||
*/
|
||||
unspecified_type compute_scalar_product_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ComputeSquaredLength_3`
|
||||
*/
|
||||
unspecified_type compute_squared_length_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructCrossProductVector_3`
|
||||
*/
|
||||
unspecified_type construct_cross_product_vector_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructMidpoint_3`
|
||||
*/
|
||||
unspecified_type construct_midpoint_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructVector_3`
|
||||
*/
|
||||
unspecified_type construct_vector_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructScaledVector_3`
|
||||
*/
|
||||
unspecified_type construct_scaled_vector_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructSumOfVectors_3`
|
||||
*/
|
||||
unspecified_type construct_sum_of_vectors_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructTranslatedPoint_3`
|
||||
*/
|
||||
unspecified_type construct_translated_point_3_object();
|
||||
|
||||
/*!
|
||||
* returns a function object model of `Kernel::ConstructVertex_3`
|
||||
*/
|
||||
unspecified_type construct_vertex_3_object();
|
||||
|
||||
/*!
|
||||
* returns a predicate object model of `Kernel::IsDegenerate_3`
|
||||
*/
|
||||
unspecified_type is_degenerate_3_object();
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*!
|
||||
\ingroup PkgConstrainedTriangulation3Concepts
|
||||
\cgalConcept
|
||||
|
||||
The concept `ConformingConstrainedDelaunayTriangulationVertexBase_3` refines the concept
|
||||
`TriangulationVertexBase_3` and describes the requirements for a base vertex class of
|
||||
the `CGAL::Conforming_constrained_Delaunay_triangulation_3` class.
|
||||
|
||||
\cgalRefines{TriangulationVertexBase_3, BaseWithTimeStamp}
|
||||
|
||||
\cgalHasModelsBegin
|
||||
\cgalHasModels{CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3}
|
||||
\cgalHasModelsEnd
|
||||
|
||||
\sa `ConformingConstrainedDelaunayTriangulationCellBase_3`
|
||||
|
||||
*/
|
||||
class ConformingConstrainedDelaunayTriangulationVertexBase_3 {
|
||||
public:
|
||||
|
||||
/// @name Access Functions
|
||||
///
|
||||
/// The following functions return a reference to an object of type
|
||||
/// `CGAL::Conforming_constrained_Delaunay_triangulation_vertex_data_3`, that contains
|
||||
/// the per-vertex data required by the implementation of the
|
||||
/// `CGAL::Conforming_constrained_Delaunay_triangulation_3` class.
|
||||
/// @{
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_vertex_data_3& ccdt_3_data();
|
||||
const CGAL::Conforming_constrained_Delaunay_triangulation_vertex_data_3& ccdt_3_data() const;
|
||||
/// @}
|
||||
}
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_CT_3
|
||||
\anchor userchapterct3
|
||||
|
||||
\cgalAutoToc
|
||||
\author Laurent Rineau and Jane Tournois
|
||||
|
||||
\cgalFigureAnchor{CT_3_pyramid_fig}
|
||||
<img src="cdt_title_pyramid.png" style="max-width:60%;min-width=20%"/>
|
||||
<BR>
|
||||
|
||||
\section CT_3_CCDT_3 Constrained Triangulations in 3D
|
||||
|
||||
3D triangulations partition space and are useful in many applications. In some cases, it is
|
||||
important to ensure that specific faces, such as those representing the sharp features of an object, appear in the output.
|
||||
When a triangulation exactly respects these constraints, it is called a _constrained_ triangulation.
|
||||
However, it is sometimes only possible to preserve the geometry of the constraints, but not their exact
|
||||
combinatorics. In such cases, additional points, called _Steiner_ _points_, must be inserted. This process
|
||||
results in a _conforming_ triangulation.
|
||||
|
||||
This package implements an algorithm for constructing conforming triangulations of 3D polygonal
|
||||
constraints. Specifically, it requires that these piecewise linear constraints are provided as a
|
||||
_piecewise linear complex_ (PLC). The resulting triangulations are of type `Triangulation_3`,
|
||||
as described in the chapter \ref PkgTriangulation3.
|
||||
|
||||
The article by Cohen-Steiner et al. \cgalCite{cgal:cohen2002conforming} discusses the problem of
|
||||
constructing conforming Delaunay triangulations and proposes an algorithm to address it.
|
||||
Si et al.'s work \cgalCite{si2005meshing}, \cgalCite{cgal:si2008cdt3}, \cgalCite{si2015tetgen},
|
||||
presents an algorithm for computing conforming constrained
|
||||
Delaunay triangulations in 3D.
|
||||
|
||||
\section CT_3_definitions Definitions
|
||||
|
||||
This section introduces the key concepts necessary to understand and use this package effectively.
|
||||
|
||||
\subsection CT_3_PLC Piecewise Linear Complex
|
||||
|
||||
A _piecewise linear complex_ (PLC) is the three-dimensional generalization of a
|
||||
planar straight-line graph. It consists of a finite set of vertices, edges, and polygonal faces
|
||||
that satisfy the following properties:
|
||||
|
||||
- The vertices and edges of the PLC form a simplicial complex: two edges may intersect only at a
|
||||
shared vertex.
|
||||
- The boundary of each polygonal face in the PLC is an ordered list of vertices from the PLC, forming
|
||||
one closed loop.
|
||||
- Each polygonal face must be a simple polygon, i.e., its edges don't intersect,
|
||||
except consecutive edges, which intersect at their common vertex.
|
||||
- Each polygonal face must be planar, meaning all its vertices lie on the same plane.
|
||||
- Each polygonal face may have one or more holes, each of them also represented by an ordered list of vertices
|
||||
from the PLC, forming a closed loop.
|
||||
- If two polygons in the PLC intersect, their intersection is a union of edges and vertices from the
|
||||
PLC. In particular, the interiors of two polygons cannot overlap.
|
||||
|
||||
Polygons in a PLC may be non-convex and may have holes.
|
||||
|
||||
\cgalFigureAnchor{CT_3_plc_fig}
|
||||
<center>
|
||||
<img src="plc.png" style="max-width:60%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{CT_3_plc_fig}
|
||||
A piecewise linear complex, composed of planar faces connected by edges and vertices.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
|
||||
\subsection CT_3_CDT Conforming Constrained Delaunay Triangulation
|
||||
|
||||
The algorithms developed in this package are designed to compute a constrained Delaunay
|
||||
triangulation that contains a given set of polygonal constraints in 3D as a subcomplex.
|
||||
|
||||
A triangulation is a _Delaunay triangulation_ if the circumscribing sphere of any simplex
|
||||
in the triangulation contains no vertex in its interior (see chapter \ref PkgTriangulation3
|
||||
for more details on Delaunay triangulations).
|
||||
|
||||
A _constrained Delaunay triangulation_ of a PLC is a constrained triangulation that is as close as
|
||||
possible to being Delaunay, given that some faces are marked as _constrained_. More precisely, a
|
||||
triangulation is _constrained Delaunay_ if, for any simplex \f$s\f$ of the triangulation, the
|
||||
interior of its circumscribing sphere contains no vertex of the triangulation that is _visible_ from
|
||||
any point in the interior of the simplex \f$s\f$. Two points are _visible_ if the open line segment
|
||||
joining them does not intersect any polygonal face of the PLC, except for polygons that are coplanar with
|
||||
the segment.
|
||||
|
||||
In 3D, constrained triangulations do not always exist. This can be demonstrated using the example of
|
||||
Schönhardt polyhedra \cgalCite{s-udzvd-28} (see \cgalFigureRef{CT_3_schonhardt_fig}),
|
||||
\cgalCite{b-ip-48a}. Shewchuk \cgalCite{cgal:shewchuk1998condition} demonstrated that for any PLC,
|
||||
there exists a refined
|
||||
version of the original PLC that admits a constrained Delaunay triangulation. This refinement is
|
||||
achieved by adding Steiner vertices to the input edges and polygons. The constrained triangulation
|
||||
built on this refined PLC is known as a _conforming constrained Delaunay triangulation_ (CCDT for
|
||||
short). \cgalFigureRef{CT_3_plc2cdt_fig} illustrates an example of a conforming constrained
|
||||
Delaunay triangulation constructed from a PLC.
|
||||
|
||||
|
||||
\cgalFigureAnchor{CT_3_schonhardt_fig}
|
||||
<center>
|
||||
<img src="schonhardt.png" style="max-width:25%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{CT_3_schonhardt_fig}
|
||||
A Schönhardt polyhedron.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
|
||||
\cgalFigureAnchor{CT_3_plc2cdt_fig}
|
||||
<center>
|
||||
<img src="plc_to_cdt.png" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{CT_3_plc2cdt_fig}
|
||||
Left: PLC (360 vertices);
|
||||
Right: CCDT (2452 vertices).
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
The algorithm implemented in this package is based on the work of Hang Si et al., who developed particular
|
||||
algorithms for constructing conforming constrained Delaunay triangulations from PLCs.
|
||||
The corresponding implementation takes with floating point numbers as coordinates
|
||||
\cgalCite{si2005meshing}, \cgalCite{cgal:si2008cdt3}, \cgalCite{si2015tetgen}.
|
||||
|
||||
|
||||
\section CT_3_design Software Design
|
||||
|
||||
\subsection CT_3_representation_of_PLCs Representation of Piecewise Linear Complexes
|
||||
|
||||
There is no universal or canonical way to represent all possible PLCs in \cgal.
|
||||
|
||||
Any polyhedral surface is a PLC, so any model of `FaceListGraph`, such as `CGAL::Surface_mesh`, can be
|
||||
used to represent such a PLC.
|
||||
In this representation, the geometric structure of the PLC is directly mapped to the elements
|
||||
of the `CGAL::Surface_mesh`:
|
||||
- vertices of the PLC geometrically correspond to vertices of the surface mesh,
|
||||
- edges of the PLC correspond to edges of the surface mesh,
|
||||
- and polygonal faces of the PLC correspond to faces of the surface mesh,
|
||||
covering the surface of a geometric object.
|
||||
However, PLCs represented in this way are limited to being
|
||||
manifold (that is, each edge belongs to exactly two faces), and their faces cannot have holes.
|
||||
|
||||
A PLC can also be represented as a polygon soup: a collection of vertices and a set of polygons, where
|
||||
each polygon is defined by an ordered list of vertices, without explicit connectivity information between
|
||||
polygons. For a polygon soup to represent a valid PLC, its polygons must satisfy the properties described
|
||||
in the previous section. This approach allows for the representation of non-manifold geometries; however,
|
||||
polygons in a polygon soup cannot have holes.
|
||||
|
||||
This package also provides a way to group polygons into distinct surface patches using a property map,
|
||||
named `plc_face_id`.
|
||||
Each polygon can be assigned a _patch_ identifier, allowing multiple polygons to form a continuous surface patch,
|
||||
which may include holes. Some necessary geometric conditions must be satisfied for these patches to be
|
||||
used in the conforming constrained Delaunay triangulation construction:
|
||||
- Each patch must be planar, meaning all polygonal faces in the patch lie on the same plane;
|
||||
- The polygonal faces of the patch must not intersect except at their shared edges.
|
||||
|
||||
When this property map is provided, the input PLC is interpreted in terms of its polygonal faces,
|
||||
edges and vertices as follows:
|
||||
- Each polygonal face of the PLC is defined as the union of input polygons sharing the same patch identifier;
|
||||
- The edges of the PLC are those from the surface mesh or polygon soup that satisfy one of the following conditions:
|
||||
-- they are adjacent to only one polygonal face;
|
||||
-- they are adjacent to two polygonal faces with different patch identifiers;
|
||||
-- they are adjacent to more than two polygonal faces with differing patch identifiers, indicating non-manifold features of the PLC.
|
||||
- The vertices of the PLC are the ones lying on the boundaries of surface patches in the original surface mesh or polygon soup.
|
||||
|
||||
\subsection CT_3_api API
|
||||
|
||||
This package provides a primary class, `CGAL::Conforming_constrained_Delaunay_triangulation_3`.
|
||||
This class is templated by a
|
||||
geometric traits class and an underlying triangulation class, allowing for flexibility and
|
||||
customization.
|
||||
|
||||
In addition to the main class, the package includes several auxiliary classes that define the types
|
||||
of vertices, cells, and associated metadata used within the triangulation. These supporting classes
|
||||
enable users to extend or adapt the triangulation data structure to their specific needs.
|
||||
|
||||
Two overloads of the constructor function \link
|
||||
PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh
|
||||
`CGAL::make_conforming_constrained_Delaunay_triangulation_3()`\endlink are provided to facilitate the creation
|
||||
of a `CGAL::Conforming_constrained_Delaunay_triangulation_3` object from either a surface mesh or a polygon soup.
|
||||
|
||||
\subsection CT_3_geomtraits Traits and Kernel Choice
|
||||
|
||||
The requirements for geometric objects and operations are specified by the traits class concept
|
||||
`ConformingConstrainedDelaunayTriangulationTraits_3`. Any CGAL kernel is a model of this concept.
|
||||
However, because this package builds upon the 3D Triangulation package, it inherits the requirement
|
||||
that the traits class must provide exact predicates.
|
||||
|
||||
A key aspect of this algorithm is the creation of new points, known as Steiner points, which are
|
||||
inserted on the segments and polygons of the input PLC. If a traits class with inexact constructions
|
||||
is used, it cannot be guaranteed that these points will lie exactly on the intended segments or polygons.
|
||||
As a result, the output will only approximate the input, with the accuracy limited by the rounding
|
||||
of the computed Steiner points.
|
||||
|
||||
Furthermore, when using inexact constructions, the algorithm may fail if the input PLC contains
|
||||
non-adjacent simplices that are too close to each other. In such cases, the triangulation process
|
||||
will emit an error if the distance between simplices falls below an internally computed threshold.
|
||||
An error message describing the involved simplices will be displayed on the standard output.
|
||||
If the issue is caused by poorly shaped triangles, functions such as
|
||||
`CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` may help resolve the problem.
|
||||
|
||||
\section CT_3_examples Examples
|
||||
|
||||
\subsection CT_3_example_ccdt Build a Conforming Constrained Delaunay Triangulation
|
||||
|
||||
The following example illustrates how to use the helper function
|
||||
`CGAL::make_conforming_constrained_Delaunay_triangulation_3()` to construct a conforming constrained
|
||||
Delaunay triangulation from a given PLC.
|
||||
|
||||
The triangulation is saved in the MEDIT file format, using the
|
||||
\link PkgCDT3IOFunctions `CGAL::IO::write_MEDIT()` \endlink function.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3.cpp }
|
||||
|
||||
|
||||
\subsection CT_3_example_ccdt_soup Build a Conforming Constrained Delaunay Triangulation from a Polygon Soup
|
||||
|
||||
You can also construct a conforming constrained Delaunay triangulation from a polygon soup.
|
||||
The following example demonstrates how to create such a triangulation from a collection of polygons
|
||||
without explicit connectivity information.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/ccdt_3_from_soup.cpp }
|
||||
|
||||
|
||||
\subsection CT_3_example_ccdt_fimap Build a Conforming Constrained Delaunay Triangulation with Known Polygon Identifiers
|
||||
|
||||
If the user already knows the set of polygonal face identifiers to associate with each PLC face, this information can be
|
||||
provided and preserved throughout the construction of the conforming constrained Delaunay
|
||||
triangulation.
|
||||
|
||||
The following example demonstrates how to detect planar surface patches and remesh them as coarsely
|
||||
as possible using
|
||||
\link CGAL::Polygon_mesh_processing::remesh_planar_patches(const TriangleMeshIn&,PolygonMeshOut&,const NamedParametersIn&,const NamedParametersOut&) `CGAL::Polygon_mesh_processing::remesh_planar_patches()` \endlink
|
||||
from the \ref PkgPolygonMeshProcessing package.
|
||||
The resulting patches and segmentation are then used to build a conforming constrained Delaunay triangulation.
|
||||
|
||||
When the named parameter `plc_face_id` is specified, each constrained facet in the 3D triangulation
|
||||
is assigned to the corresponding input PLC face, as identified by the provided property map.
|
||||
If this parameter is not specified, each input polygonal face is assigned a unique face index.
|
||||
|
||||
Figure \cgalFigureRef{CT_3_ccdt_examples_fig} shows the benefit of using the `plc_face_id` property map.
|
||||
On the last line of the figure, the input PLC is enriched with a segmentation of the planar faces,
|
||||
provided via the `plc_face_id` property map. In the resulting conforming constrained Delaunay triangulation,
|
||||
only the boundary edges of the PLC faces are constrained, while the other edges never get inserted as
|
||||
edges of the 3D triangulation.
|
||||
|
||||
Without the `plc_face_id` property map, all edges of the PLC faces are constrained,
|
||||
each PLC face is considered as a constraint,
|
||||
possibly resulting in a 3D triangulation with surfaces that are more refined than necessary.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fimap.cpp}
|
||||
|
||||
\cgalFigureRef{CT_3_ccdt_examples_fig} shows the input and output of this triangulation construction example.
|
||||
|
||||
|
||||
\subsection CT_3_example_ccdt_region_growing_fimap Build a Conforming Constrained Delaunay Triangulation with Detected Polygon Identifiers
|
||||
|
||||
If the user does not know the set of polygonal face identifiers to associate with each PLC face, this information can be
|
||||
automatically detected using the
|
||||
\link CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces(const PolygonMesh& mesh,RegionMap region_map,const NamedParameters& np) `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()`\endlink
|
||||
function from the \ref PkgPolygonMeshProcessing package.
|
||||
|
||||
The following example demonstrates how to detect planar surface patches and build a conforming
|
||||
constrained Delaunay triangulation using the detected segmentation. The named parameter `plc_face_id`
|
||||
is used to associate each facet of the triangulation with the corresponding input PLC face.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/ccdt_3_fimap_region_growing.cpp}
|
||||
|
||||
|
||||
\subsection CT_3_examples_preprocessing Preprocessing the Input for Conforming Constrained Delaunay Triangulations
|
||||
|
||||
Given a PLC, the algorithms in this package can construct a conforming constrained Delaunay triangulation, provided
|
||||
the input surface can be represented as a valid surface mesh or a collection of surface meshes,
|
||||
and does not contain self-intersections.
|
||||
Several preprocessing functions are available in the \ref PkgPolygonMeshProcessing package to help ensure these
|
||||
preconditions are met.
|
||||
|
||||
The following example demonstrates how to construct a conforming constrained Delaunay triangulation from
|
||||
an input mesh that is not triangulated and may contain self-intersections,
|
||||
using autorefinement.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/ccdt_3_after_autorefinement.cpp }
|
||||
|
||||
The function
|
||||
\link CGAL::Polygon_mesh_processing::does_self_intersect(const FaceRange&, const TriangleMesh&, const NamedParameters&) `CGAL::Polygon_mesh_processing::does_self_intersect()` \endlink
|
||||
is used to detect self-intersections,
|
||||
but it requires the input mesh to be triangulated. Therefore, the input mesh must first be triangulated
|
||||
using
|
||||
\link CGAL::Polygon_mesh_processing::triangulate_faces(FaceRange,PolygonMesh&,const NamedParameters&) `CGAL::Polygon_mesh_processing::triangulate_faces()`\endlink
|
||||
before performing the self-intersection check.
|
||||
|
||||
If self-intersections are found, the triangulated mesh is converted into a triangle soup, which is then
|
||||
processed with
|
||||
\link CGAL::Polygon_mesh_processing::autorefine_triangle_soup(PointRange&,TriangleRange&,const NamedParameters&) `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()`\endlink
|
||||
to resolve the self-intersections.
|
||||
|
||||
|
||||
\subsection CT_3_example_remesh Remeshing a Conforming Constrained Delaunay Triangulation
|
||||
|
||||
After constructing the triangulation, you can improve its quality or adapt it to a specific sizing
|
||||
field by applying the
|
||||
\link CGAL::tetrahedral_isotropic_remeshing(CGAL::Triangulation_3<Traits, TDS, SLDS>&, const SizingFunction&, const NamedParameters&) `CGAL::tetrahedral_isotropic_remeshing()`\endlink
|
||||
function from the \ref PkgTetrahedralRemeshing package.
|
||||
|
||||
The following example demonstrates how to remesh a conforming constrained Delaunay triangulation.
|
||||
|
||||
\cgalExample{Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp }
|
||||
|
||||
|
||||
\subsection CT_3_examples_figure Figures
|
||||
|
||||
The following table of figures (\cgalFigureRef{CT_3_ccdt_examples_fig}) illustrates some results of the examples provided in this package.
|
||||
The left column shows the input PLC, while the right column displays the resulting conforming
|
||||
constrained Delaunay triangulation.
|
||||
|
||||
From top to bottom, the lines show different input PLC, from the same input triangulated surface and,
|
||||
for each of them, the resulting conforming constrained Delaunay triangulation.
|
||||
The input data are:
|
||||
<ul>
|
||||
<li> the input PLC with no preprocessing;
|
||||
<li> the input PLC with a segmentation of the surface patches done with `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()` as done in example \ref CT_3_example_ccdt_region_growing_fimap;</li>
|
||||
<li> the input PLC, remeshed and not triangulated, with a segmentation of the surface patches, done with `CGAL::Polygon_mesh_processing::remesh_planar_patches()` as in example \ref CT_3_example_ccdt_fimap;</li>
|
||||
<li> the input PLC, isotropically remeshed, with a segmentation of the surface patches, done with `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()` as in example \ref CT_3_example_ccdt_region_growing_fimap.</li>
|
||||
</ul>
|
||||
|
||||
On the fourth line, the input PLC is remeshed using `CGAL::Polygon_mesh_processing::isotropic_remeshing()`.
|
||||
The resulting conforming constrained Delaunay triangulation contains fewer vertices than the input
|
||||
remeshed and segmented input PLC. This reduction occurs because only the boundary edges of the PLC faces
|
||||
are marked as constraints in the triangulation;
|
||||
interior edges that do not lie on the boundaries of surface patches (as defined by `plc_face_id`) are ignored.
|
||||
As a result, these non-boundary edges are omitted from the triangulation, leading to a coarser triangulation.
|
||||
|
||||
\cgalFigureAnchor{CT_3_ccdt_examples_fig}
|
||||
<center>
|
||||
<img src="ccdt_examples.png" style="max-width:50%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{CT_3_ccdt_examples_fig}
|
||||
A collection of conforming constrained Delaunay triangulations built from different inputs.
|
||||
The left column shows the input PLC, while the right column displays the resulting 3D triangulation.<br>
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
|
||||
\section CT_3_history Implementation History
|
||||
|
||||
The initial version of this package was implemented by Laurent Rineau and released in
|
||||
\cgal 6.1 (2025). Jane Tournois contributed to the documentation and helped improve the API.
|
||||
The package design and algorithms are grounded in the theoretical work of
|
||||
Hang Si et al. on meshing algorithms \cgalCite{si2005meshing}, \cgalCite{si2015tetgen}.
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Constrained Triangulations"
|
||||
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/plc.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/schonhardt.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/plc_to_cdt.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/ccdt_fpmap.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/cdt_title_pyramid.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/ccdt_examples.png
|
||||
QUIET = YES
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*!
|
||||
\defgroup PkgConstrainedTriangulation3Ref Reference Manual
|
||||
|
||||
\defgroup PkgConstrainedTriangulation3Concepts Concepts
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\defgroup PkgConstrainedTriangulation3Classes Classes and Class Templates
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\defgroup PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh Free Functions for Creating Conforming Constrained Delaunay Triangulations
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\defgroup PkgCDT3IOFunctions Output Functions
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\defgroup PkgDrawCDT_3 Draw a 3D Constrained Triangulation
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\defgroup PkgConstrainedTriangulation3Functions Other Functions
|
||||
\ingroup PkgConstrainedTriangulation3Ref
|
||||
|
||||
\addtogroup PkgConstrainedTriangulation3Ref
|
||||
\cgalPkgDescriptionBegin{3D Constrained Triangulations,PkgConstrainedTriangulation3}
|
||||
\cgalPkgPicture{small-pyramid.png}
|
||||
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Laurent Rineau and Jane Tournois}
|
||||
\cgalPkgDesc{This package implements the construction of a 3D Constrained Delaunay triangulation.
|
||||
This triangulation is a generalization of a 3D Delaunay Triangulation which conforms to the set of faces
|
||||
of a 3D _piecewise linear complex_ (PLC), ensuring that these faces are part of the triangulation.
|
||||
As not all PLCs are tetrahedralizable,
|
||||
the algorithm may insert Steiner points to construct the constrained triangulation.
|
||||
}
|
||||
\cgalPkgManuals{Chapter_CT_3,PkgConstrainedTriangulation3Ref}
|
||||
\cgalPkgSummaryEnd
|
||||
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{6.1}
|
||||
\cgalPkgDependsOn{\ref PkgTriangulation3 "3D Triangulations"}
|
||||
\cgalPkgBib{cgal:rt-cdt3}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{CGAL Lab,CGALlab.zip}
|
||||
\cgalPkgShortInfoEnd
|
||||
|
||||
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
\cgalCRPSection{Concepts}
|
||||
|
||||
- `ConformingConstrainedDelaunayTriangulationTraits_3`
|
||||
- `ConformingConstrainedDelaunayTriangulationVertexBase_3`
|
||||
- `ConformingConstrainedDelaunayTriangulationCellBase_3`
|
||||
|
||||
\cgalCRPSection{Functions}
|
||||
|
||||
- \link PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh `CGAL::make_conforming_constrained_Delaunay_triangulation_3()` \endlink: the main function to create
|
||||
a conforming constrained Delaunay triangulation in 3D, an instance of the class template
|
||||
`CGAL::Conforming_constrained_Delaunay_triangulation_3`.
|
||||
- `CGAL::Tetrahedral_remeshing::get_remeshing_triangulation()`
|
||||
|
||||
\cgalCRPSubsection{Classes}
|
||||
|
||||
- `CGAL::Conforming_constrained_Delaunay_triangulation_3<Traits, Triangulation>`
|
||||
- `CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<Traits, Vertex_base>`
|
||||
- `CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<Traits, Cell_base>`
|
||||
|
||||
\cgalCRPSection{Draw a 3D Constrained Triangulation}
|
||||
|
||||
- \link PkgDrawCDT_3 `CGAL::draw()` \endlink
|
||||
|
||||
\cgalCRPSection{Output Functions}
|
||||
|
||||
- \link PkgCDT3IOFunctions `CGAL::IO::write_MEDIT()` \endlink
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Basic_viewer
|
||||
BGL
|
||||
Kernel_23
|
||||
Manual
|
||||
Polygon_mesh_processing
|
||||
Property_map
|
||||
SMDS_3
|
||||
STL_Extension
|
||||
Stream_support
|
||||
Surface_mesh
|
||||
TDS_3
|
||||
Tetrahedral_remeshing
|
||||
Triangulation_3
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*!
|
||||
\example Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3.cpp
|
||||
@brief
|
||||
|
||||
Simple example demonstrating the usage of the Constrained_triangulation_3 package.<br>
|
||||
|
||||
It constructs a 3D constrained Delaunay triangulation from a polygon mesh.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example Constrained_triangulation_3/ccdt_3_from_soup.cpp
|
||||
@brief
|
||||
|
||||
Simple example demonstrating the usage of the Constrained_triangulation_3 package.<br>
|
||||
|
||||
It constructs a constrained Delaunay triangulation from a polygon soup.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example Constrained_triangulation_3/remesh_constrained_Delaunay_triangulation_3.cpp
|
||||
@brief
|
||||
|
||||
How to use `CGAL::tetrahedral_isotropic_remeshing` with a constrained Delaunay triangulation.
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\example Constrained_triangulation_3/conforming_constrained_Delaunay_triangulation_3_fimap.cpp
|
||||
@brief
|
||||
|
||||
From a non-manifold OFF file, construct the constrained Delaunay triangulation.
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\example Constrained_triangulation_3/ccdt_3_after_autorefinement.cpp
|
||||
@brief
|
||||
|
||||
From a self-intersecting and non-triangulated surface in an OFF file,
|
||||
construct the constrained Delaunay triangulation after preprocessing by autorefinement.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example Constrained_triangulation_3/ccdt_3_check_preconditions.cpp
|
||||
\example Constrained_triangulation_3/ccdt_3_fimap_region_growing.cpp
|
||||
\example Constrained_triangulation_3/ccdt_3_from_soup_fimap.cpp
|
||||
\example Constrained_triangulation_3/ccdt_3_preprocessing.cpp
|
||||
*/
|
||||
|
After Width: | Height: | Size: 219 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -0,0 +1,40 @@
|
|||
cmake_minimum_required(VERSION 3.12...3.31)
|
||||
project(Constrained_triangulation_3_Examples)
|
||||
|
||||
find_package(CGAL REQUIRED COMPONENTS Qt6)
|
||||
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
add_compile_definitions(QT_NO_KEYWORDS)
|
||||
|
||||
create_single_source_cgal_program(conforming_constrained_Delaunay_triangulation_3.cpp)
|
||||
create_single_source_cgal_program(conforming_constrained_Delaunay_triangulation_3_fimap.cpp)
|
||||
create_single_source_cgal_program(ccdt_3_from_soup.cpp)
|
||||
create_single_source_cgal_program(ccdt_3_from_soup_fimap.cpp)
|
||||
create_single_source_cgal_program(ccdt_3_after_autorefinement.cpp)
|
||||
create_single_source_cgal_program(ccdt_3_preprocessing.cpp)
|
||||
create_single_source_cgal_program(ccdt_3_check_preconditions.cpp)
|
||||
create_single_source_cgal_program(remesh_constrained_Delaunay_triangulation_3.cpp)
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program(ccdt_3_fimap_region_growing.cpp)
|
||||
target_link_libraries(ccdt_3_fimap_region_growing PUBLIC CGAL::Eigen3_support)
|
||||
endif()
|
||||
|
||||
if(CGAL_Qt6_FOUND)
|
||||
target_link_libraries(conforming_constrained_Delaunay_triangulation_3 PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(ccdt_3_from_soup PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(ccdt_3_from_soup_fimap PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(ccdt_3_after_autorefinement PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(ccdt_3_preprocessing PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
target_link_libraries(ccdt_3_check_preconditions PUBLIC CGAL::CGAL_Basic_viewer)
|
||||
else()
|
||||
message(STATUS "NOTICE: The example 'conforming_constrained_Delaunay_triangulation_3' cannot draw the result without Qt6.")
|
||||
endif()
|
||||
|
||||
find_package(TBB QUIET)
|
||||
include(CGAL_TBB_support)
|
||||
if(TARGET CGAL::TBB_support)
|
||||
target_link_libraries(ccdt_3_from_soup_fimap PUBLIC CGAL::TBB_support)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/draw_constrained_triangulation_3.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = K::Point_3;
|
||||
using Surface_mesh = CGAL::Surface_mesh<Point>;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const auto filename = (argc > 1) ? argv[1]
|
||||
: CGAL::data_file_path("meshes/spheres_intersecting.off");
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(!CGAL::IO::read_polygon_mesh(filename, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Number of facets in " << filename << ": "
|
||||
<< mesh.number_of_faces() << "\n";
|
||||
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_3<K> ccdt;
|
||||
|
||||
if(PMP::does_self_intersect(mesh))
|
||||
{
|
||||
std::cout << "Mesh self-intersects, performing autorefine...\n";
|
||||
|
||||
// use a polygon soup as container as the output will most likely be non-manifold
|
||||
std::vector<Point> points;
|
||||
std::vector<std::vector<std::size_t>> polygons;
|
||||
PMP::polygon_mesh_to_polygon_soup(mesh, points, polygons);
|
||||
PMP::autorefine_triangle_soup(points, polygons);
|
||||
std::cout << "Number of input triangles after autorefine: "
|
||||
<< polygons.size() << "\n";
|
||||
|
||||
if(PMP::does_polygon_soup_self_intersect(points, polygons))
|
||||
{
|
||||
std::cerr << "Error: mesh still self-intersects after autorefine\n";
|
||||
std::cerr << "Run autorefinement again with an exact kernel ";
|
||||
std::cerr << "such as CGAL::Exact_predicates_exact_constructions_kernel \n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(points, polygons);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh);
|
||||
}
|
||||
std::cout << "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
CGAL::draw(ccdt);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/boost/graph/copy_face_graph.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
|
||||
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/draw_constrained_triangulation_3.h>
|
||||
#include <CGAL/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/IO/polygon_soup_io.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = K::Point_3;
|
||||
using Surface_mesh = CGAL::Surface_mesh<Point>;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
// Function to verify preconditions for a mesh input
|
||||
bool verify_preconditions_mesh(const Surface_mesh& mesh)
|
||||
{
|
||||
if(CGAL::is_triangle_mesh(mesh))
|
||||
return !CGAL::Polygon_mesh_processing::does_self_intersect(mesh);
|
||||
|
||||
Surface_mesh triangle_mesh;
|
||||
CGAL::copy_face_graph(mesh, triangle_mesh);
|
||||
bool tri_ok = CGAL::Polygon_mesh_processing::triangulate_faces(triangle_mesh);
|
||||
if(!tri_ok)
|
||||
return false;
|
||||
|
||||
return !CGAL::Polygon_mesh_processing::does_self_intersect(triangle_mesh);
|
||||
}
|
||||
|
||||
// Function to verify preconditions for a polygon soup input
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool verify_preconditions_soup(const PointRange& points, const PolygonRange& polygons)
|
||||
{
|
||||
return !CGAL::Polygon_mesh_processing::does_polygon_soup_self_intersect(points, polygons);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const auto filename = (argc > 1) ? argv[1]
|
||||
: CGAL::data_file_path("meshes/cubes.off");
|
||||
|
||||
// Read polygon soup
|
||||
using Points = std::vector<Point>;
|
||||
using PLC_face = std::vector<std::size_t>;
|
||||
using PLC_faces = std::vector<PLC_face>;
|
||||
Points points;
|
||||
PLC_faces faces;
|
||||
if(!CGAL::IO::read_polygon_soup(filename, points, faces))
|
||||
{
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// When possible, convert polygon soup to polygon mesh
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(faces))
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, faces, mesh);
|
||||
std::cout << "Number of facets in " << filename << ": " << mesh.number_of_faces() << "\n";
|
||||
}
|
||||
|
||||
// Verify preconditions for the mesh input
|
||||
const bool is_polygon_mesh = !mesh.is_empty();
|
||||
if(is_polygon_mesh && !verify_preconditions_mesh(mesh))
|
||||
{
|
||||
std::cerr << "Error: input mesh is not a valid input for CCDT_3\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if(!verify_preconditions_soup(points, faces))
|
||||
{
|
||||
std::cerr << "Error: input polygon soup is not a valid input for CCDT_3\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Build conforming constrained Delaunay triangulation
|
||||
auto ccdt = is_polygon_mesh
|
||||
? CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh)
|
||||
: CGAL::make_conforming_constrained_Delaunay_triangulation_3(points, faces);
|
||||
|
||||
// Print mesh details
|
||||
if(ccdt.number_of_constrained_facets() == 0)
|
||||
{
|
||||
std::cerr << "Error: no constrained facets in the CDT.\n";
|
||||
std::cerr << "Invalid input.\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::cout << "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
// Output
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
CGAL::draw(ccdt);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/region_growing.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
using Mesh = CGAL::Surface_mesh<K::Point_3>;
|
||||
using face_descriptor = boost::graph_traits<Mesh>::face_descriptor;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cross_quad.off");
|
||||
|
||||
Mesh mesh;
|
||||
if(!PMP::IO::read_polygon_mesh(filename, mesh)) {
|
||||
std::cerr << "Invalid input." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " facets\n";
|
||||
|
||||
auto [face_patch_map, _] =mesh.add_property_map<face_descriptor, std::size_t>("f:patch_id");
|
||||
|
||||
const auto bbox = CGAL::Polygon_mesh_processing::bbox(mesh);
|
||||
const double bbox_max_span = (std::max)({bbox.x_span(), bbox.y_span(), bbox.z_span()});
|
||||
|
||||
std::cout << "Merging facets into coplanar patches..." << std::endl;
|
||||
|
||||
auto number_of_patches = CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces(
|
||||
mesh,
|
||||
face_patch_map,
|
||||
CGAL::parameters::maximum_distance(bbox_max_span * 1.e-6)
|
||||
.maximum_angle(5.));
|
||||
|
||||
for(auto f: faces(mesh))
|
||||
{
|
||||
// if region growing did not assign a patch id, assign one
|
||||
if(get(face_patch_map, f) == static_cast<std::size_t>(-1)) {
|
||||
put(face_patch_map, f, number_of_patches++);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Number of patches: " << number_of_patches << std::endl;
|
||||
|
||||
filename = argc > 2 ? argv[2] : "mesh.ply";
|
||||
CGAL::IO::write_polygon_mesh(filename, mesh,
|
||||
CGAL::parameters::stream_precision(17)
|
||||
.use_binary_mode(false)
|
||||
.face_patch_map(face_patch_map));
|
||||
std::cout << "-- Wrote segmented mesh to \"" << filename << "\"\n";
|
||||
|
||||
std::cout << "Creating a conforming constrained Delaunay triangulation...\n";
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh,
|
||||
CGAL::parameters::plc_face_id(face_patch_map));
|
||||
|
||||
std::cout << "Number of vertices in the CDT: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n'
|
||||
<< "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
// Write the CDT to a file, with the PLC face ids
|
||||
filename = argc > 3 ? argv[3] : "out.mesh";
|
||||
std::ofstream out(filename);
|
||||
out.precision(17);
|
||||
CGAL::IO::write_MEDIT(out, ccdt, CGAL::parameters::with_plc_face_id(true));
|
||||
std::cout << "-- Wrote CDT to \"" << filename << "\"\n";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/IO/polygon_soup_io.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/draw_constrained_triangulation_3.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cubes.off");
|
||||
|
||||
std::vector<K::Point_3> points;
|
||||
std::vector<std::vector<std::size_t>> polygons;
|
||||
if(!CGAL::IO::read_polygon_soup(filename, points, polygons)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Read " << points.size() << " vertices and "
|
||||
<< polygons.size() << " polygons" << std::endl;
|
||||
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(points, polygons);
|
||||
|
||||
std::cout << "Number of vertices in the CDT: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n'
|
||||
<< "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
CGAL::draw(ccdt);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/draw_constrained_triangulation_3.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = K::Point_3;
|
||||
using Surface_mesh = CGAL::Surface_mesh<Point>;
|
||||
using face_descriptor = Surface_mesh::Face_index;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cubes_one_patch_id_per_cc.off");
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(!CGAL::IO::read_polygon_mesh(filename, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto fpmap = mesh.add_property_map<face_descriptor, std::size_t>("f:cc_id").first;
|
||||
|
||||
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " polygons" << std::endl;
|
||||
|
||||
PMP::connected_components(mesh, fpmap);
|
||||
|
||||
std::cout << "Number of connected components: "
|
||||
<< fpmap[*std::max_element(mesh.faces_begin(), mesh.faces_end(),
|
||||
[&](face_descriptor f1, face_descriptor f2) {
|
||||
return fpmap[f1] < fpmap[f2];
|
||||
})] + 1
|
||||
<< std::endl;
|
||||
|
||||
std::vector<K::Point_3> points;
|
||||
std::vector<std::vector<std::size_t>> polygons;
|
||||
PMP::polygon_mesh_to_polygon_soup(mesh, points, polygons);
|
||||
|
||||
auto polygon_to_patch_id = [&](std::size_t i) {
|
||||
return fpmap[*std::next(mesh.faces_begin(), i)];
|
||||
};
|
||||
|
||||
auto soup_fpmap = boost::make_function_property_map<std::size_t>(polygon_to_patch_id);
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(
|
||||
points, polygons, CGAL::parameters::plc_face_id(soup_fpmap));
|
||||
|
||||
std::cout << "Number of vertices in the CDT: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n'
|
||||
<< "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
CGAL::draw(ccdt);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/boost/graph/copy_face_graph.h>
|
||||
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/draw_constrained_triangulation_3.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = K::Point_3;
|
||||
using Surface_mesh = CGAL::Surface_mesh<Point>;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const auto filename = (argc > 1) ? argv[1]
|
||||
: CGAL::data_file_path("meshes/mpi_and_sphere.off");
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(!CGAL::IO::read_polygon_mesh(filename, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Number of facets in " << filename << ": "
|
||||
<< mesh.number_of_faces() << "\n";
|
||||
|
||||
// Check if the mesh is a triangle mesh
|
||||
bool triangle_mesh = CGAL::is_triangle_mesh(mesh);
|
||||
if(!triangle_mesh)
|
||||
{
|
||||
std::cout << "Mesh is not a triangle mesh, triangulate faces"
|
||||
<< " to check self-intersections...\n";
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> trimesh;
|
||||
CGAL::copy_face_graph(mesh, trimesh);
|
||||
PMP::triangulate_faces(trimesh);
|
||||
|
||||
if(PMP::does_self_intersect(trimesh))
|
||||
{
|
||||
std::cout << "Mesh self-intersects, let's keep the triangulated version"
|
||||
<< " for future autorefinement\n";
|
||||
CGAL::copy_face_graph(trimesh, mesh);
|
||||
mesh = std::move(trimesh);
|
||||
triangle_mesh = true;
|
||||
}
|
||||
}
|
||||
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_3<K> ccdt;
|
||||
if(triangle_mesh && PMP::does_self_intersect(mesh))
|
||||
{
|
||||
std::cout << "Mesh is a self-intersecting triangle mesh, perform autorefinement...\n";
|
||||
|
||||
// use a polygon soup as container as the output will most likely be non-manifold
|
||||
std::vector<K::Point_3> points;
|
||||
std::vector<std::vector<std::size_t>> polygons;
|
||||
PMP::polygon_mesh_to_polygon_soup(mesh, points, polygons);
|
||||
PMP::autorefine_triangle_soup(points, polygons);
|
||||
std::cout << "Number of facets after preprocessing: "
|
||||
<< polygons.size() << "\n";
|
||||
|
||||
if(PMP::does_polygon_soup_self_intersect(points, polygons))
|
||||
{
|
||||
std::cerr << "Error: mesh still self-intersects after autorefine\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(points, polygons);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Number of facets after preprocessing: "
|
||||
<< mesh.number_of_faces() << "\n";
|
||||
|
||||
ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh);
|
||||
}
|
||||
|
||||
std::cout << "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
CGAL::draw(ccdt);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(!CGAL::IO::read_polygon_mesh(filename, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " faces" << std::endl;
|
||||
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh);
|
||||
|
||||
//! [use of ccdt.triangulation()]
|
||||
std::cout << "Number of vertices in the CDT: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n';
|
||||
//! [use of ccdt.triangulation()]
|
||||
std::cout << "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
std::ofstream ofs(argc > 2 ? argv[2] : "out.mesh");
|
||||
ofs.precision(17);
|
||||
CGAL::IO::write_MEDIT(ofs, ccdt);
|
||||
|
||||
//! [move ccdt to tr]
|
||||
auto tr = std::move(ccdt).triangulation();
|
||||
// Now `tr` is a valid `CGAL::Triangulation_3` object that can be used for further processing.
|
||||
// and the triangulation of `ccdt` is empty.
|
||||
std::cout << "Number of vertices in the triangulation `tr`: "
|
||||
<< tr.number_of_vertices() << '\n';
|
||||
std::cout << "Number of vertices in `ccdt`: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n';
|
||||
assert(ccdt.triangulation().number_of_vertices() == 0);
|
||||
//! [move ccdt to tr]
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/remesh_planar_patches.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
using Mesh = CGAL::Surface_mesh<K::Point_3>;
|
||||
using face_descriptor = boost::graph_traits<Mesh>::face_descriptor;
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/cross.off");
|
||||
|
||||
Mesh input;
|
||||
if(!CGAL::Polygon_mesh_processing::IO::read_polygon_mesh(filename, input)) {
|
||||
std::cerr << "Invalid input." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Read " << input.number_of_vertices() << " vertices and "
|
||||
<< input.number_of_faces() << " facets\n";
|
||||
|
||||
Mesh mesh;
|
||||
auto plc_facet_map = get(CGAL::face_patch_id_t<int>(), mesh);
|
||||
|
||||
// Remesh planar patches and segment the mesh into planar patches
|
||||
CGAL::Polygon_mesh_processing::remesh_planar_patches(input, mesh,
|
||||
CGAL::parameters::default_values(),
|
||||
CGAL::parameters::face_patch_map(plc_facet_map)
|
||||
.do_not_triangulate_faces(true));
|
||||
|
||||
|
||||
filename = argc > 2 ? argv[2] : "mesh.ply";
|
||||
CGAL::IO::write_polygon_mesh(filename, mesh,
|
||||
CGAL::parameters::stream_precision(17));
|
||||
std::cout << "Wrote segmented mesh to " << filename << "\n";
|
||||
|
||||
// Create a conforming constrained Delaunay triangulation from the mesh
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh,
|
||||
CGAL::parameters::plc_face_id(plc_facet_map));
|
||||
|
||||
std::cout << "Number of vertices in the CDT: "
|
||||
<< ccdt.triangulation().number_of_vertices() << '\n'
|
||||
<< "Number of constrained facets in the CDT: "
|
||||
<< ccdt.number_of_constrained_facets() << '\n';
|
||||
|
||||
filename = argc > 3 ? argv[3] : "out.mesh";
|
||||
std::ofstream out(filename);
|
||||
out.precision(17);
|
||||
CGAL::IO::write_MEDIT(out, ccdt, CGAL::parameters::with_plc_face_id(true));
|
||||
std::cout << "Wrote CDT to " << filename << "\n";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_cell_base_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h>
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h>
|
||||
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/tetrahedral_remeshing.h>
|
||||
|
||||
#include <CGAL/IO/File_medit.h>
|
||||
#include <CGAL/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/IO/write_MEDIT.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <unordered_set>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
using Vbb = CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3<K>;
|
||||
using Vb = CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<K, Vbb>;
|
||||
|
||||
using Cbb = CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3<K>;
|
||||
using Cb = CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<K, Cbb>;
|
||||
|
||||
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
|
||||
using Tr = CGAL::Triangulation_3<K, Tds>;
|
||||
using CCDT = CGAL::Conforming_constrained_Delaunay_triangulation_3<K, Tr>;
|
||||
|
||||
// Triangulation for Remeshing
|
||||
using CCDT_Tr = CCDT::Triangulation;
|
||||
using Triangulation_3 = CGAL::Triangulation_3<K, CCDT_Tr::Triangulation_data_structure>;
|
||||
|
||||
using Vertex_handle = Triangulation_3::Vertex_handle;
|
||||
using Vertex_pair = std::pair<Vertex_handle, Vertex_handle>;
|
||||
using Constraints_set = std::unordered_set<Vertex_pair, boost::hash<Vertex_pair>>;
|
||||
using Constraints_pmap = CGAL::Boolean_property_map<Constraints_set>;
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
|
||||
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
if(!CGAL::IO::read_polygon_mesh(filename, mesh))
|
||||
{
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
CCDT ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3<CCDT>(mesh);
|
||||
|
||||
std::ofstream out("ccdt.mesh");
|
||||
CGAL::IO::write_MEDIT(out, ccdt);
|
||||
out.close();
|
||||
|
||||
Constraints_set constraints;
|
||||
Constraints_pmap constraints_pmap(constraints);
|
||||
|
||||
namespace np = CGAL::parameters;
|
||||
namespace Tet_remesh = CGAL::Tetrahedral_remeshing;
|
||||
Tr tr = Tet_remesh::get_remeshing_triangulation(std::move(ccdt),
|
||||
np::edge_is_constrained_map(constraints_pmap));
|
||||
std::cout << "Number of vertices in tr: " << tr.number_of_vertices() << std::endl;
|
||||
|
||||
CGAL::tetrahedral_isotropic_remeshing(tr,
|
||||
1., // target edge length
|
||||
np::number_of_iterations(3)
|
||||
.edge_is_constrained_map(constraints_pmap));
|
||||
|
||||
std::cout << "Number of vertices in tr: "
|
||||
<< tr.number_of_vertices() << std::endl;
|
||||
|
||||
std::ofstream ofs("tr.mesh");
|
||||
CGAL::IO::write_MEDIT(ofs, tr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,993 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CONFORMING_DELAUNAY_TRIANGULATION_3_H
|
||||
#define CGAL_CONFORMING_DELAUNAY_TRIANGULATION_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Constrained_triangulation_3/internal/config.h>
|
||||
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_data_3.h>
|
||||
#include <CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h>
|
||||
#include <CGAL/Triangulation_segment_traverser_3.h>
|
||||
#include <CGAL/unordered_flat_set.h>
|
||||
|
||||
#include <CGAL/Mesh_3/io_signature.h>
|
||||
#include <CGAL/IO/File_binary_mesh_3.h>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/map.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <bitset>
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <typename T_3>
|
||||
class Conforming_Delaunay_triangulation_3 : public T_3 {
|
||||
public:
|
||||
static constexpr bool t_3_is_not_movable =
|
||||
CGAL::cdt_3_msvc_2019_or_older() || false == CGAL::is_nothrow_movable_v<T_3>;
|
||||
using Geom_traits = typename T_3::Geom_traits;
|
||||
using Vertex_handle = typename T_3::Vertex_handle;
|
||||
using Edge = typename T_3::Edge;
|
||||
using Facet = typename T_3::Facet;
|
||||
using Cell_handle = typename T_3::Cell_handle;
|
||||
using Point = typename T_3::Point;
|
||||
using Line = typename T_3::Geom_traits::Line_3;
|
||||
using Locate_type = typename T_3::Locate_type;
|
||||
|
||||
inline static With_offset_tag with_offset{};
|
||||
inline static With_point_tag with_point{};
|
||||
inline static With_point_and_info_tag with_point_and_info{};
|
||||
|
||||
Conforming_Delaunay_triangulation_3(const Geom_traits& gt = Geom_traits())
|
||||
: T_3(gt)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
struct Compare_vertex_handle {
|
||||
const T_3* tr;
|
||||
Compare_vertex_handle(const T_3* tr) : tr(tr) {}
|
||||
bool operator()(const Vertex_handle va, const Vertex_handle vb) const {
|
||||
return va < vb;
|
||||
}
|
||||
};
|
||||
|
||||
using Constraint_hierarchy =
|
||||
Polyline_constraint_hierarchy_2<Vertex_handle, Compare_vertex_handle, Point>;
|
||||
public:
|
||||
using Constrained_polyline_id = typename Constraint_hierarchy::Constraint_id;
|
||||
|
||||
protected:
|
||||
using Subconstraint = typename Constraint_hierarchy::Subconstraint;
|
||||
|
||||
auto display_vert(Vertex_handle v) const{
|
||||
std::stringstream os;
|
||||
os.precision(17);
|
||||
os << IO::oformat(v, with_point);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
auto display_subcstr(Subconstraint subconstraint) const {
|
||||
auto [va, vb] = subconstraint;
|
||||
std::stringstream os;
|
||||
os << "(" << IO::oformat(va, with_offset) << ", " << IO::oformat(vb, with_offset) << ")"
|
||||
<< ": [ " << display_vert(va) << " - " << display_vert(vb) << " ]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
class Insert_in_conflict_visitor
|
||||
{
|
||||
Conforming_Delaunay_triangulation_3<T_3>* self;
|
||||
public:
|
||||
Insert_in_conflict_visitor(Conforming_Delaunay_triangulation_3* self) : self(self) {}
|
||||
|
||||
template <class InputIterator>
|
||||
void process_cells_in_conflict(InputIterator cell_it, InputIterator end) {
|
||||
auto d = self->tr().dimension();
|
||||
for( ; cell_it != end; ++cell_it )
|
||||
for( int i = 0; i < d; ++i )
|
||||
for( int j = i+1; j <= d; ++j ) {
|
||||
auto v1 = (*cell_it)->vertex(i);
|
||||
auto v2 = (*cell_it)->vertex(j);
|
||||
if(self->tr().is_infinite(v1) || self->tr().is_infinite(v2)) continue;
|
||||
if(self->use_finite_edges_map()) {
|
||||
if(v1 > v2) std::swap(v1, v2);
|
||||
auto v1_index = v1->time_stamp();
|
||||
[[maybe_unused]] auto nb_erased = self->all_finite_edges[v1_index].erase(v2);
|
||||
if constexpr (cdt_3_can_use_cxx20_format()) if(self->debug_finite_edges_map() && nb_erased > 0) {
|
||||
std::cerr << cdt_3_format("erasing edge {} {}\n", self->display_vert((std::min)(v1, v2)),
|
||||
self->display_vert((std::max)(v1, v2)));
|
||||
}
|
||||
}
|
||||
auto [contexts_begin, contexts_end] =
|
||||
self->constraint_hierarchy.contexts(v1, v2);
|
||||
if(contexts_begin != contexts_end) {
|
||||
self->add_to_subconstraints_to_conform(v1, v2, contexts_begin->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void after_insertion(Vertex_handle v) const {
|
||||
if(!self->use_finite_edges_map()) return;
|
||||
CGAL_assertion(self->dimension() > 1);
|
||||
self->incident_edges(v, boost::make_function_output_iterator([this](Edge e) { self->new_edge(e); }));
|
||||
self->incident_cells(v, boost::make_function_output_iterator([this, v](Cell_handle c) {
|
||||
auto v_index = c->index(v);
|
||||
if(self->dimension() == 2) {
|
||||
auto j = self->cw(v_index);
|
||||
auto k = self->ccw(v_index);
|
||||
self->new_edge(Edge(c, j, k));
|
||||
} else {
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
auto j = self->vertex_triple_index(v_index, i);
|
||||
auto k = self->vertex_triple_index(v_index, self->cw(i));
|
||||
self->new_edge(Edge(c, j, k));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void reinsert_vertices(Vertex_handle v) const { after_insertion(v); }
|
||||
Vertex_handle replace_vertex(Cell_handle c, int index, const Point& ) const
|
||||
{
|
||||
return c->vertex(index);
|
||||
}
|
||||
void hide_point(Cell_handle, const Point& ) const {}
|
||||
|
||||
void insert_Steiner_point_on_constraint([[maybe_unused]] Constrained_polyline_id constraint,
|
||||
[[maybe_unused]] Vertex_handle va,
|
||||
[[maybe_unused]] Vertex_handle vb,
|
||||
[[maybe_unused]] Vertex_handle v_Steiner) const
|
||||
{
|
||||
}
|
||||
|
||||
Vertex_handle insert_in_triangulation(const Point& p, Locate_type lt, Cell_handle c, int li, int lj) {
|
||||
return self->insert_impl_do_not_split(p, lt, c, li, lj, *this);
|
||||
}
|
||||
};
|
||||
|
||||
auto make_subconstraint(Vertex_handle va, Vertex_handle vb) {
|
||||
return make_sorted_pair(va, vb);
|
||||
}
|
||||
|
||||
void add_to_subconstraints_to_conform(Vertex_handle va, Vertex_handle vb,
|
||||
Constrained_polyline_id id) {
|
||||
const auto pair = make_subconstraint(va, vb);
|
||||
#if CGAL_DEBUG_CDT_3 & 32
|
||||
std::cerr << "tr().subconstraints_to_conform.push("
|
||||
<< display_subcstr(pair) << ")\n";
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
subconstraints_to_conform.push({pair, id});
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
Constrained_polyline_id insert_constrained_edge_impl(Vertex_handle va, Vertex_handle vb,
|
||||
Visitor&) {
|
||||
if(va != vb) {
|
||||
if(segment_vertex_epsilon != 0.) {
|
||||
auto [min_dist, min_vertex] = min_distance_and_vertex_between_constraint_and_encroaching_vertex(va, vb);
|
||||
check_segment_vertex_distance_or_throw(va, vb, min_vertex, CGAL::to_double(min_dist),
|
||||
Check_distance::NON_SQUARED_DISTANCE);
|
||||
}
|
||||
const Constrained_polyline_id c_id = constraint_hierarchy.insert_constraint(va, vb);
|
||||
pair_of_vertices_to_cid.emplace(make_sorted_pair(va, vb), c_id);
|
||||
// traverse all the vertices along [va, vb] and add pairs of consecutive
|
||||
// vertices as sub-constraints.
|
||||
std::for_each(tr().segment_traverser_simplices_begin(va, vb), tr().segment_traverser_simplices_end(),
|
||||
[&, prev = Vertex_handle{}](auto simplex) mutable {
|
||||
// std::cerr << "- " << oformat(simplex, With_point_tag{}) << '\n';
|
||||
if(simplex.dimension() == 0) {
|
||||
const auto v = static_cast<Vertex_handle>(simplex);
|
||||
v->ccdt_3_data().set_on_constraint(c_id);
|
||||
if(prev != Vertex_handle{}) {
|
||||
if(v != vb) {
|
||||
v->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::STEINER_ON_EDGE);
|
||||
constraint_hierarchy.add_Steiner(prev, vb, v);
|
||||
}
|
||||
add_to_subconstraints_to_conform(prev, v, c_id);
|
||||
}
|
||||
prev = v;
|
||||
}
|
||||
});
|
||||
return c_id;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void new_edge(Edge e)
|
||||
{
|
||||
if(!update_all_finite_edges_) return;
|
||||
auto [v1, v2] = make_sorted_pair(tr().vertices(e));
|
||||
if(tr().is_infinite(v1) || tr().is_infinite(v2))
|
||||
return;
|
||||
[[maybe_unused]] auto [_, inserted] = all_finite_edges[v1->time_stamp()].insert(v2);
|
||||
if constexpr (cdt_3_can_use_cxx20_format()) if (debug_finite_edges_map() && inserted) {
|
||||
if(v2 < v1) std::swap(v1, v2);
|
||||
std::cerr << cdt_3_format("new_edge({}, {})\n", display_vert(v1), display_vert(v2));
|
||||
}
|
||||
}
|
||||
|
||||
void new_cell(Cell_handle c) {
|
||||
auto d = tr().dimension();
|
||||
for(int i = 0; i < d; ++i) {
|
||||
for(int j = i+1; j <= d; ++j) {
|
||||
new_edge(Edge(c, i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto new_cells_output_iterator()
|
||||
{
|
||||
return boost::function_output_iterator([this](Cell_handle c) {
|
||||
if(use_finite_edges_map())
|
||||
this->new_cell(c);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
Vertex_handle insert_impl_do_not_split(const Point &p, Locate_type lt, Cell_handle c,
|
||||
int li, int lj, Visitor& visitor)
|
||||
{
|
||||
switch (tr().dimension()) {
|
||||
case 3: {
|
||||
typename T_3::Conflict_tester_3 tester(p, this);
|
||||
auto v = tr().insert_in_conflict(p, lt, c, li, lj, tester,
|
||||
visitor);
|
||||
new_vertex(v);
|
||||
return v;
|
||||
} // dim 3
|
||||
case 2: {
|
||||
typename T_3::Conflict_tester_2 tester(p, this);
|
||||
auto v = tr().insert_in_conflict(p, lt, c, li, lj, tester, visitor);
|
||||
if(use_finite_edges_map()) {
|
||||
new_vertex(v);
|
||||
tr().incident_edges(v, boost::make_function_output_iterator([&](Edge e) { this->new_edge(e); }));
|
||||
}
|
||||
return v;
|
||||
} // dim 2
|
||||
default:
|
||||
// dimension <= 1
|
||||
// Do not use the generic insert.
|
||||
auto v = tr().insert(p, c);
|
||||
if(use_finite_edges_map()) {
|
||||
new_vertex(v);
|
||||
all_finite_edges.clear();
|
||||
if (debug_finite_edges_map()) std::cerr << "all_finite_edges.clear()\n";
|
||||
for(auto e: tr().all_edges()) {
|
||||
new_edge(e);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
Vertex_handle insert_impl(const Point &p, Locate_type lt, Cell_handle c,
|
||||
int li, int lj, Visitor& visitor)
|
||||
{
|
||||
Vertex_handle v1, v2;
|
||||
bool split_constrained_edge = false;
|
||||
if(lt == T_3::EDGE) {
|
||||
v1 = c->vertex(li);
|
||||
v2 = c->vertex(lj);
|
||||
if(constraint_hierarchy.is_subconstraint(v1, v2)) {
|
||||
split_constrained_edge = true;
|
||||
}
|
||||
}
|
||||
Vertex_handle new_vertex = insert_impl_do_not_split(p, lt, c, li, lj, visitor);
|
||||
if(split_constrained_edge) {
|
||||
constraint_hierarchy.split_constraint(v1, v2, new_vertex);
|
||||
}
|
||||
return new_vertex;
|
||||
}
|
||||
|
||||
void update_bbox(const Point& p) {
|
||||
bbox = bbox + p.bbox();
|
||||
if(max_bbox_edge_length) {
|
||||
update_max_bbox_edge_length();
|
||||
}
|
||||
}
|
||||
|
||||
void update_max_bbox_edge_length() {
|
||||
double d_x = bbox.xmax() - bbox.xmin();
|
||||
double d_y = bbox.ymax() - bbox.ymin();
|
||||
double d_z = bbox.zmax() - bbox.zmin();
|
||||
|
||||
max_bbox_edge_length = (std::max)(d_x, (std::max)(d_y, d_z));
|
||||
}
|
||||
|
||||
public:
|
||||
void set_segment_vertex_epsilon(double epsilon) {
|
||||
segment_vertex_epsilon = epsilon;
|
||||
}
|
||||
|
||||
bool debug_Steiner_points() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::Steiner_points)];
|
||||
}
|
||||
|
||||
void debug_Steiner_points(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::Steiner_points), b);
|
||||
}
|
||||
|
||||
bool debug_input_faces() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::input_faces)];
|
||||
}
|
||||
|
||||
void debug_input_faces(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::input_faces), b);
|
||||
}
|
||||
|
||||
bool debug_missing_region() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::missing_region)];
|
||||
}
|
||||
|
||||
void debug_missing_region(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::missing_region), b);
|
||||
}
|
||||
|
||||
bool debug_regions() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::regions)];
|
||||
}
|
||||
|
||||
void debug_regions(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::regions), b);
|
||||
}
|
||||
|
||||
bool debug_copy_triangulation_into_hole() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::copy_triangulation_into_hole)];
|
||||
}
|
||||
|
||||
void debug_copy_triangulation_into_hole(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::copy_triangulation_into_hole), b);
|
||||
}
|
||||
|
||||
bool debug_validity() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::validity)];
|
||||
}
|
||||
|
||||
void debug_validity(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::validity), b);
|
||||
}
|
||||
|
||||
bool use_older_cavity_algorithm() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::use_older_cavity_algorithm)];
|
||||
}
|
||||
|
||||
void use_older_cavity_algorithm(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::use_older_cavity_algorithm), b);
|
||||
}
|
||||
|
||||
bool debug_finite_edges_map() const {
|
||||
return debug_flags[static_cast<int>(Debug_flags::debug_finite_edges_map)];
|
||||
}
|
||||
|
||||
void debug_finite_edges_map(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::debug_finite_edges_map), b);
|
||||
}
|
||||
|
||||
bool use_finite_edges_map() const {
|
||||
return update_all_finite_edges_ && debug_flags[static_cast<int>(Debug_flags::use_finite_edges_map)];
|
||||
}
|
||||
|
||||
void use_finite_edges_map(bool b) {
|
||||
debug_flags.set(static_cast<int>(Debug_flags::use_finite_edges_map), b);
|
||||
}
|
||||
|
||||
Vertex_handle insert(const Point &p, Locate_type lt, Cell_handle c,
|
||||
int li, int lj)
|
||||
{
|
||||
update_bbox(p);
|
||||
auto v = insert_impl(p, lt, c, li, lj, insert_in_conflict_visitor);
|
||||
restore_Delaunay(insert_in_conflict_visitor);
|
||||
return v;
|
||||
}
|
||||
|
||||
Vertex_handle insert(const Point &p, Cell_handle start = {}) {
|
||||
Locate_type lt;
|
||||
int li, lj;
|
||||
|
||||
Cell_handle c = tr().locate(p, lt, li, lj, start);
|
||||
return insert(p, lt, c, li, lj);
|
||||
}
|
||||
|
||||
Constrained_polyline_id insert_constrained_edge(Vertex_handle va, Vertex_handle vb)
|
||||
{
|
||||
const auto id = insert_constrained_edge_impl(va, vb, insert_in_conflict_visitor);
|
||||
restore_Delaunay(insert_in_conflict_visitor);
|
||||
return id;
|
||||
}
|
||||
|
||||
bool is_edge(Vertex_handle va, Vertex_handle vb) const {
|
||||
const bool is_edge_v1 =
|
||||
((debug_finite_edges_map() && use_finite_edges_map()) || !use_finite_edges_map()) && tr().tds().is_edge(va, vb);
|
||||
|
||||
if(use_finite_edges_map() && va > vb) std::swap(va, vb);
|
||||
const auto va_index = va->time_stamp();
|
||||
const bool is_edge_v2 =
|
||||
use_finite_edges_map() && all_finite_edges[va_index].find(vb) != all_finite_edges[va_index].end();
|
||||
|
||||
if(debug_finite_edges_map() && use_finite_edges_map() && is_edge_v1 != is_edge_v2) {
|
||||
std::cerr << "!! Inconsistent edge status\n";
|
||||
std::cerr << " -> constraint " << display_vert(va) << " " << display_vert(vb) << '\n';
|
||||
std::cerr << " -> edge " << (is_edge_v1 ? "is" : "is not") << " in the triangulation\n";
|
||||
std::cerr << " -> edge " << (is_edge_v2 ? "is" : "is not") << " in all_finite_edges\n";
|
||||
debug_dump("bug-inconsistent-edge-status");
|
||||
CGAL_error();
|
||||
}
|
||||
const bool is_edge = use_finite_edges_map() ? is_edge_v2 : is_edge_v1;
|
||||
return is_edge;
|
||||
}
|
||||
|
||||
using T_3::is_edge;
|
||||
|
||||
bool is_conforming() const {
|
||||
return std::all_of(constraint_hierarchy.subconstraints_begin(),
|
||||
constraint_hierarchy.subconstraints_end(),
|
||||
[this](const auto &sc) {
|
||||
const auto [va, vb] = sc;
|
||||
const auto is_edge = this->is_edge(va, vb);
|
||||
#if CGAL_DEBUG_CDT_3 & 128 && CGAL_CAN_USE_CXX20_FORMAT
|
||||
std::cerr << cdt_3_format("is_conforming>> Edge is 3D: {} ({} , {})\n",
|
||||
is_edge,
|
||||
CGAL::IO::oformat(va, with_point_and_info),
|
||||
CGAL::IO::oformat(vb, with_point_and_info));
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
return is_edge;
|
||||
});
|
||||
}
|
||||
|
||||
enum class Check_distance { SQUARED_DISTANCE, NON_SQUARED_DISTANCE };
|
||||
|
||||
void check_segment_vertex_distance_or_throw(Vertex_handle va,
|
||||
Vertex_handle vb,
|
||||
Vertex_handle min_vertex,
|
||||
double min_dist,
|
||||
Check_distance option)
|
||||
{
|
||||
if(!max_bbox_edge_length) {
|
||||
update_max_bbox_edge_length();
|
||||
}
|
||||
if((option == Check_distance::NON_SQUARED_DISTANCE && min_dist < segment_vertex_epsilon * *max_bbox_edge_length) ||
|
||||
(option == Check_distance::SQUARED_DISTANCE &&
|
||||
min_dist < CGAL::square(segment_vertex_epsilon * *max_bbox_edge_length)))
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.precision(std::cerr.precision());
|
||||
ss << "A constrained segment is too close to a vertex.\n";
|
||||
ss << " -> vertex " << display_vert(min_vertex) << '\n';
|
||||
ss << " -> constrained segment " << display_vert(va) << " - " << display_vert(vb) << '\n';
|
||||
ss << " -> distance = " << min_dist << '\n';
|
||||
ss << " -> max_bbox_edge_length = " << *max_bbox_edge_length << '\n';
|
||||
CGAL_error_msg(ss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
auto ancestors_of_Steiner_vertex_on_edge(Vertex_handle v) const {
|
||||
std::pair<Vertex_handle, Vertex_handle> result;
|
||||
CGAL_precondition(v->ccdt_3_data().is_Steiner_vertex_on_edge());
|
||||
CGAL_assertion(v->ccdt_3_data().number_of_incident_constraints() == 1);
|
||||
const auto v_time_stamp = v->time_stamp();
|
||||
const auto constrained_polyline_id = v->ccdt_3_data().constrained_polyline_id(*this);
|
||||
const auto first = this->constraint_hierarchy.vertices_in_constraint_begin(constrained_polyline_id);
|
||||
const auto end = this->constraint_hierarchy. vertices_in_constraint_end(constrained_polyline_id);
|
||||
std::cerr << "ancestors_of_Steiner_vertex_on_edge " << display_vert(v) << '\n';
|
||||
for(auto it = first; it != end; ++it) {
|
||||
std::cerr << " - " << display_vert(*it) << '\n';
|
||||
}
|
||||
CGAL_assertion(first != end);
|
||||
const auto last = std::prev(this->constraint_hierarchy.vertices_in_constraint_end(constrained_polyline_id));
|
||||
CGAL_assertion(first != last);
|
||||
CGAL_assertion((*first)->time_stamp() < v_time_stamp);
|
||||
CGAL_assertion((*last)->time_stamp() < v_time_stamp);
|
||||
for(auto it = first; (*it) != v; ++it) {
|
||||
if((*it)->time_stamp() < v_time_stamp) {
|
||||
result.first = *it;
|
||||
}
|
||||
CGAL_assertion(it != last);
|
||||
}
|
||||
for(auto it = last; (*it) != v; --it) {
|
||||
if((*it)->time_stamp() < v_time_stamp) {
|
||||
result.second = *it;
|
||||
}
|
||||
CGAL_assertion(it != first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto min_distance_and_vertex_between_constraint_and_encroaching_vertex(Vertex_handle va, Vertex_handle vb) const {
|
||||
struct Result {
|
||||
typename T_3::Geom_traits::FT min_dist = (std::numeric_limits<double>::max)();
|
||||
Vertex_handle v = {};
|
||||
} result;
|
||||
const auto vector_of_encroaching_vertices = encroaching_vertices(va, vb);
|
||||
for(auto v: vector_of_encroaching_vertices) {
|
||||
const auto dist = CGAL::approximate_sqrt(squared_distance(tr().point(v), Line{tr().point(va), tr().point(vb)}));
|
||||
if(dist < result.min_dist) {
|
||||
result = Result{dist, v};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool write_missing_segments_file(std::ostream &out) {
|
||||
bool any_missing_segment = false;
|
||||
std::for_each(
|
||||
constraint_hierarchy.subconstraints_begin(), constraint_hierarchy.subconstraints_end(),
|
||||
[this, &out, &any_missing_segment](const auto &sc) {
|
||||
const auto [v0, v1] = sc;
|
||||
if (!this->is_edge(v0, v1)) {
|
||||
out << "2 " << this->tr().point(v0) << " " << this->tr().point(v1)
|
||||
<< '\n';
|
||||
any_missing_segment = true;
|
||||
}
|
||||
});
|
||||
return any_missing_segment;
|
||||
}
|
||||
|
||||
void write_all_segments_file(std::ostream &out) {
|
||||
std::for_each(
|
||||
constraint_hierarchy.subconstraints_begin(), constraint_hierarchy.subconstraints_end(),
|
||||
[this, &out](const auto &sc) {
|
||||
const auto [v0, v1] = sc;
|
||||
out << "2 " << this->tr().point(v0) << " " << this->tr().point(v1) << '\n';
|
||||
});
|
||||
}
|
||||
|
||||
/// @{
|
||||
/// remove functions cannot be called
|
||||
void remove(Vertex_handle) = delete;
|
||||
void remove_cluster() = delete;
|
||||
/// @}
|
||||
|
||||
static std::string io_signature() {
|
||||
return Get_io_signature<T_3>()();
|
||||
}
|
||||
protected:
|
||||
void debug_dump(std::string filename) const {
|
||||
{
|
||||
std::ofstream dump(filename + ".binary.cgal", std::ios::binary);
|
||||
CGAL::IO::save_binary_file(dump, *this);
|
||||
}
|
||||
{
|
||||
std::ofstream dump(filename + "_point.xyz");
|
||||
dump.precision(17);
|
||||
for(auto vh: this->finite_vertex_handles()){
|
||||
dump << this->point(vh) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void restore_Delaunay(Visitor& visitor) {
|
||||
update_all_finite_edges();
|
||||
while(!subconstraints_to_conform.empty()) {
|
||||
const auto [subconstraint, constrained_polyline_id] = subconstraints_to_conform.top();
|
||||
subconstraints_to_conform.pop();
|
||||
const auto [va, vb] = subconstraint;
|
||||
if(!constraint_hierarchy.is_subconstraint(va, vb)) {
|
||||
continue;
|
||||
}
|
||||
#if CGAL_DEBUG_CDT_3 & 32
|
||||
std::cerr << "tr().subconstraints_to_conform.pop()="
|
||||
<< display_subcstr(subconstraint) << "\n";
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
conform_subconstraint(subconstraint, constrained_polyline_id, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
Vertex_handle insert_Steiner_point_on_subconstraint(
|
||||
Point steiner_pt, Cell_handle hint,
|
||||
Subconstraint subconstraint, Constrained_polyline_id constraint, Visitor& visitor)
|
||||
{
|
||||
const Vertex_handle va = subconstraint.first;
|
||||
const Vertex_handle vb = subconstraint.second;
|
||||
Locate_type lt;
|
||||
int li, lj;
|
||||
const Cell_handle c = tr().locate(steiner_pt, lt, li, lj, hint);
|
||||
const Vertex_handle v = visitor.insert_in_triangulation(steiner_pt, lt, c, li, lj);
|
||||
v->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::STEINER_ON_EDGE);
|
||||
if(lt != T_3::VERTEX) {
|
||||
v->ccdt_3_data().set_on_constraint(constraint);
|
||||
}
|
||||
constraint_hierarchy.add_Steiner(va, vb, v);
|
||||
visitor.insert_Steiner_point_on_constraint(constraint, va, vb, v);
|
||||
add_to_subconstraints_to_conform(va, v, constraint);
|
||||
add_to_subconstraints_to_conform(v, vb, constraint);
|
||||
|
||||
new_vertex(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Return `true` if a Steiner point was inserted
|
||||
template <typename Visitor>
|
||||
bool conform_subconstraint(Subconstraint subconstraint,
|
||||
Constrained_polyline_id constraint,
|
||||
Visitor& visitor)
|
||||
{
|
||||
const Vertex_handle va = subconstraint.first;
|
||||
const Vertex_handle vb = subconstraint.second;
|
||||
CGAL_assertion(va != vb);
|
||||
if(!this->is_edge(va, vb)) {
|
||||
const auto& [steiner_pt, hint, ref_vertex] = construct_Steiner_point(constraint, subconstraint);
|
||||
[[maybe_unused]] const auto v =
|
||||
insert_Steiner_point_on_subconstraint(steiner_pt, hint, subconstraint, constraint, visitor);
|
||||
if(debug_Steiner_points()) {
|
||||
const auto [c_start, c_end] = constraint_extremities(constraint);
|
||||
std::cerr << "(" << IO::oformat(va, with_offset) << ", " << IO::oformat(vb, with_offset) << ")";
|
||||
std::cerr << ": [ " << display_vert(c_start) << " - " << display_vert(c_end) << " ] ";
|
||||
std::cerr << " new vertex " << display_vert(v) << '\n';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Constrained_polyline_id constraint_from_extremities(Vertex_handle va, Vertex_handle vb) const {
|
||||
if(va->ccdt_3_data().number_of_incident_constraints() == 0 || vb->ccdt_3_data().number_of_incident_constraints() == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
auto it = pair_of_vertices_to_cid.find(make_sorted_pair(va, vb));
|
||||
if(it != pair_of_vertices_to_cid.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
// @TODO: cleanup the rest of the function, and `constraint_around`
|
||||
Constrained_polyline_id c_id = constraint_around(va, vb, false);
|
||||
if(c_id != Constrained_polyline_id{}) return c_id;
|
||||
c_id = constraint_around(vb, va, false);
|
||||
if(c_id != Constrained_polyline_id{}) return c_id;
|
||||
c_id = constraint_around(va, vb, true);
|
||||
return c_id;
|
||||
}
|
||||
|
||||
auto constraint_extremities(Constrained_polyline_id c_id) const {
|
||||
CGAL_assertion(std::find(this->constraint_hierarchy.constraints_begin(),
|
||||
this->constraint_hierarchy.constraints_end(), c_id) != this->constraint_hierarchy.constraints_end());
|
||||
CGAL_assertion(this->constraint_hierarchy.vertices_in_constraint_begin(c_id) !=
|
||||
this->constraint_hierarchy.vertices_in_constraint_end(c_id));
|
||||
#if CGAL_DEBUG_CDT_3 & 8
|
||||
std::cerr << "constraint " << (void*) c_id.vl_ptr() << " has "
|
||||
<< c_id.vl_ptr()->skip_size() << " vertices\n";
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
const auto begin = this->constraint_hierarchy.vertices_in_constraint_begin(c_id);
|
||||
const auto end = this->constraint_hierarchy.vertices_in_constraint_end(c_id);
|
||||
const auto c_va = *begin;
|
||||
const auto c_vb = *std::prev(end);
|
||||
return std::make_pair(c_va, c_vb);
|
||||
}
|
||||
|
||||
Constrained_polyline_id constraint_around(Vertex_handle va, Vertex_handle vb, bool expensive = true) const {
|
||||
auto constraint_id_goes_to_vb = [this, va, vb](Constrained_polyline_id c_id) {
|
||||
const auto [c_va, c_vb] = constraint_extremities(c_id);
|
||||
if (va == c_va && vb == c_vb)
|
||||
return true;
|
||||
if (vb == c_va && va == c_vb)
|
||||
return true;
|
||||
return false;
|
||||
}; // end lambda constraint_id_goes_to_vb
|
||||
if (va->ccdt_3_data().number_of_incident_constraints() == 1)
|
||||
{
|
||||
const Constrained_polyline_id c_id = va->ccdt_3_data().constrained_polyline_id(*this);
|
||||
CGAL_assertion(c_id != Constrained_polyline_id{});
|
||||
if(constraint_id_goes_to_vb(c_id)) return c_id;
|
||||
} else if (expensive == true && va->ccdt_3_data().number_of_incident_constraints() > 1) {
|
||||
boost::container::small_vector<Vertex_handle, 64> adj_vertices;
|
||||
this->finite_adjacent_vertices(va, std::back_inserter(adj_vertices));
|
||||
for(auto other_v: adj_vertices) {
|
||||
for(auto context: this->constraint_hierarchy.contexts(va, other_v)) {
|
||||
const Constrained_polyline_id c_id = context.id();
|
||||
if(constraint_id_goes_to_vb(c_id)) return c_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Constrained_polyline_id{};
|
||||
}
|
||||
|
||||
struct Construct_Steiner_point_return_type {
|
||||
typename T_3::Geom_traits::Point_3 point;
|
||||
Cell_handle hint;
|
||||
Vertex_handle reference_vertex;
|
||||
};
|
||||
|
||||
auto encroaching_vertices(Vertex_handle va, Vertex_handle vb) const {
|
||||
auto& gt = tr().geom_traits();
|
||||
auto angle_functor = gt.angle_3_object();
|
||||
|
||||
const auto& pa = tr().point(va);
|
||||
const auto& pb = tr().point(vb);
|
||||
|
||||
namespace bc = boost::container;
|
||||
bc::flat_set<Vertex_handle, std::less<Vertex_handle>,
|
||||
bc::small_vector<Vertex_handle, 256>>
|
||||
encroaching_vertices;
|
||||
auto register_vertex = [this,&encroaching_vertices](Vertex_handle v) {
|
||||
if(tr().is_infinite(v)) return;
|
||||
// std::cerr << "register_vertex " << display_vert(v) << '\n';
|
||||
encroaching_vertices.insert(v);
|
||||
};
|
||||
auto fill_encroaching_vertices = [&](const auto simplex) {
|
||||
#if CGAL_DEBUG_CDT_3 & 0x10
|
||||
std::cerr << " - " << IO::oformat(simplex, With_point_tag{}) << '\n';
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
auto visit_cell = [&](Cell_handle cell) {
|
||||
for(int i = 0, end = this->tr().dimension() + 1; i < end; ++i) {
|
||||
const auto v = cell->vertex(i);
|
||||
register_vertex(v);
|
||||
}
|
||||
};
|
||||
switch(simplex.dimension()) {
|
||||
case 3: {
|
||||
const auto cell = static_cast<Cell_handle>(simplex);
|
||||
visit_cell(cell);
|
||||
} break;
|
||||
case 2: {
|
||||
const auto [cell, facet_index] = static_cast<Facet>(simplex);
|
||||
visit_cell(cell);
|
||||
if(tr().dimension() > 2) {
|
||||
const auto [other_cell, other_index] = tr().mirror_facet({cell, facet_index});
|
||||
register_vertex(other_cell->vertex(other_index));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
auto edge = static_cast<Edge>(simplex);
|
||||
if(tr().dimension() < 3) {
|
||||
auto [cell, i, j] = edge;
|
||||
visit_cell(cell);
|
||||
if(tr().dimension() < 2) break;
|
||||
auto neighbor_cell = cell->neighbor(3 - i - j);
|
||||
visit_cell(neighbor_cell);
|
||||
break;
|
||||
}
|
||||
auto circ = tr().incident_cells(edge);
|
||||
CGAL_assertion(circ != nullptr);
|
||||
const auto end = circ;
|
||||
do {
|
||||
visit_cell(circ);
|
||||
} while(++circ != end);
|
||||
} break;
|
||||
case 0: {
|
||||
const auto v = static_cast<Vertex_handle>(simplex);
|
||||
if(v != va && v != vb) {
|
||||
std::cerr << "!! The constraint passes through a vertex!\n";
|
||||
std::cerr << " -> constraint " << display_vert(va) << " " << display_vert(vb) << '\n';
|
||||
std::cerr << " -> vertex " << display_vert(v) << '\n';
|
||||
debug_dump("bug-through-vertex");
|
||||
CGAL_error();
|
||||
}
|
||||
} break;
|
||||
default: CGAL_unreachable();
|
||||
} // end switch
|
||||
};
|
||||
std::for_each(tr().segment_traverser_simplices_begin(va, vb), tr().segment_traverser_simplices_end(),
|
||||
fill_encroaching_vertices);
|
||||
auto vector_of_encroaching_vertices = encroaching_vertices.extract_sequence();
|
||||
#if CGAL_DEBUG_CDT_3 & 0x10
|
||||
std::cerr << " -> vector_of_encroaching_vertices (before filter):\n";
|
||||
std::for_each(vector_of_encroaching_vertices.begin(),
|
||||
vector_of_encroaching_vertices.end(),
|
||||
[this](Vertex_handle v){
|
||||
std::cerr << " " << this->display_vert(v) << '\n';
|
||||
});
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
auto end = std::remove_if(vector_of_encroaching_vertices.begin(),
|
||||
vector_of_encroaching_vertices.end(),
|
||||
[va, vb, pa, pb, &angle_functor, this](Vertex_handle v) {
|
||||
if(va == v || vb == v) return true;
|
||||
return angle_functor(pa,
|
||||
this->tr().point(v),
|
||||
pb) == ACUTE;
|
||||
});
|
||||
#if CGAL_DEBUG_CDT_3 & 0x10
|
||||
std::cerr << " -> vector_of_encroaching_vertices (after filter):\n";
|
||||
std::for_each(vector_of_encroaching_vertices.begin(), end, [&](Vertex_handle v) {
|
||||
std::cerr << " " << this->display_vert(v) << " angle " << approximate_angle(pa, this->tr().point(v), pb)
|
||||
<< '\n';
|
||||
});
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
vector_of_encroaching_vertices.erase(end, vector_of_encroaching_vertices.end());
|
||||
return vector_of_encroaching_vertices;
|
||||
}
|
||||
|
||||
Construct_Steiner_point_return_type
|
||||
construct_Steiner_point(Constrained_polyline_id constrained_polyline_id, Subconstraint subconstraint)
|
||||
{
|
||||
auto& gt = tr().geom_traits();
|
||||
auto compare_angle_functor = gt.compare_angle_3_object();
|
||||
auto vector_functor = gt.construct_vector_3_object();
|
||||
auto midpoint_functor = gt.construct_midpoint_3_object();
|
||||
auto scaled_vector_functor = gt.construct_scaled_vector_3_object();
|
||||
auto sq_length_functor = gt.compute_squared_length_3_object();
|
||||
auto sc_product_functor = gt.compute_scalar_product_3_object();
|
||||
auto translate_functor = gt.construct_translated_point_3_object();
|
||||
|
||||
const Vertex_handle va = subconstraint.first;
|
||||
const Vertex_handle vb = subconstraint.second;
|
||||
const auto& pa = tr().point(va);
|
||||
const auto& pb = tr().point(vb);
|
||||
const auto [orig_va, orig_vb] = constraint_extremities(constrained_polyline_id);
|
||||
const auto& orig_pa = tr().point(orig_va);
|
||||
const auto& orig_pb = tr().point(orig_vb);
|
||||
|
||||
if(this->dimension() < 2) {
|
||||
std::cerr << "dim < 2: midpoint\n";
|
||||
return {midpoint_functor(pa, pb), va->cell(), va};
|
||||
}
|
||||
|
||||
#if CGAL_DEBUG_CDT_3 & 0x10
|
||||
std::cerr << "construct_Steiner_point( " << display_vert(va) << " , "
|
||||
<< display_vert(vb) << " )\n";
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
|
||||
const auto vector_of_encroaching_vertices = encroaching_vertices(va, vb);
|
||||
CGAL_assertion(vector_of_encroaching_vertices.size() > 0);
|
||||
|
||||
const auto reference_vertex_it = std::max_element(
|
||||
vector_of_encroaching_vertices.begin(), vector_of_encroaching_vertices.end(),
|
||||
[pa, pb, &compare_angle_functor, this](Vertex_handle v1,
|
||||
Vertex_handle v2) {
|
||||
return compare_angle_functor(pa, this->tr().point(v1), pb,
|
||||
pa, this->tr().point(v2), pb) == SMALLER;
|
||||
});
|
||||
CGAL_assertion(reference_vertex_it != vector_of_encroaching_vertices.end());
|
||||
#if CGAL_CDT_3_DEBUG_CONFORMING
|
||||
std::cerr << " -> reference point: " << display_vert(*reference_vertex_it)
|
||||
<< '\n';
|
||||
#endif // CGAL_CDT_3_DEBUG_CONFORMING
|
||||
const auto reference_vertex = *reference_vertex_it;
|
||||
const auto& reference_point = tr().point(reference_vertex);
|
||||
|
||||
const auto vector_ab = vector_functor(pa, pb);
|
||||
|
||||
if(reference_vertex->ccdt_3_data().is_Steiner_vertex_on_edge()) {
|
||||
CGAL_assertion(reference_vertex->ccdt_3_data().number_of_incident_constraints() == 1);
|
||||
const auto ref_constrained_polyline_id = reference_vertex->ccdt_3_data().constrained_polyline_id(*this);
|
||||
const auto [ref_va, ref_vb] = constraint_extremities(ref_constrained_polyline_id);
|
||||
#if CGAL_CDT_3_DEBUG_CONFORMING
|
||||
std::cerr << " reference point is on constraint: " << display_vert(ref_va)
|
||||
<< " " << display_vert(ref_vb) << '\n'
|
||||
<< " original constraint: " << display_vert(orig_va)
|
||||
<< " " << display_vert(orig_vb) << '\n';
|
||||
#endif // CGAL_CDT_3_DEBUG_CONFORMING
|
||||
const auto vector_orig_ab = vector_functor(orig_pa, orig_pb);
|
||||
const auto length_ab = CGAL::approximate_sqrt(sq_length_functor(vector_ab));
|
||||
auto return_orig_result_point =
|
||||
[&](auto lambda, Point orig_pa, Point orig_pb)
|
||||
-> Construct_Steiner_point_return_type
|
||||
{
|
||||
const auto vector_orig_ab = vector_functor(orig_pa, orig_pb);
|
||||
const auto inter_point = translate_functor(orig_pa, scaled_vector_functor(vector_orig_ab, lambda));
|
||||
const auto dist_a_result = CGAL::approximate_sqrt(sq_length_functor(vector_functor(pa, inter_point)));
|
||||
const auto ratio = dist_a_result / length_ab;
|
||||
const auto result_point = (ratio < 0.2 || ratio > 0.8)
|
||||
? midpoint_functor(pa, pb)
|
||||
: inter_point;
|
||||
|
||||
#if CGAL_CDT_3_DEBUG_CONFORMING
|
||||
std::cerr << " ref ratio = " << ratio << '\n';
|
||||
std::cerr << " -> Steiner point: " << result_point << '\n';
|
||||
#endif // CGAL_CDT_3_DEBUG_CONFORMING
|
||||
return {result_point, reference_vertex->cell(), reference_vertex};
|
||||
};
|
||||
|
||||
const auto length_orig_ab = CGAL::approximate_sqrt(sq_length_functor(vector_orig_ab));
|
||||
if(ref_va == orig_va || ref_vb == orig_va) {
|
||||
const auto vector_orig_a_ref = vector_functor(orig_pa, reference_point);
|
||||
const auto length_orig_a_ref = CGAL::approximate_sqrt(sq_length_functor(vector_orig_a_ref));
|
||||
const auto lambda = length_orig_a_ref / length_orig_ab;
|
||||
return return_orig_result_point(lambda, orig_pa, orig_pb);
|
||||
} else if(ref_va == orig_vb || ref_vb == orig_vb) {
|
||||
const auto vector_orig_b_ref = vector_functor(orig_pb, reference_point);
|
||||
const auto length_orig_b_ref = CGAL::approximate_sqrt(sq_length_functor(vector_orig_b_ref));
|
||||
const auto lambda = length_orig_b_ref / length_orig_ab;
|
||||
return return_orig_result_point(lambda, orig_pb, orig_pa);
|
||||
}
|
||||
} else {
|
||||
if(segment_vertex_epsilon > 0) {
|
||||
if(!max_bbox_edge_length) {
|
||||
update_max_bbox_edge_length();
|
||||
}
|
||||
auto sq_dist = squared_distance(reference_point, Line{orig_pa, orig_pb});
|
||||
check_segment_vertex_distance_or_throw(orig_va, orig_vb, reference_vertex, CGAL::to_double(sq_dist),
|
||||
Check_distance::SQUARED_DISTANCE);
|
||||
}
|
||||
}
|
||||
// compute the projection of the reference point
|
||||
const auto vector_a_ref = vector_functor(pa, reference_point);
|
||||
const auto lambda = sc_product_functor(vector_a_ref, vector_ab) / sq_length_functor(vector_ab);
|
||||
const auto result_point = (lambda < 0.2 || lambda > 0.8)
|
||||
? midpoint_functor(pa, pb)
|
||||
: translate_functor(pa, scaled_vector_functor(vector_ab, lambda));
|
||||
|
||||
#if CGAL_CDT_3_DEBUG_CONFORMING
|
||||
std::cerr << " lambda = " << lambda << '\n';
|
||||
std::cerr << " -> Steiner point: " << result_point << '\n';
|
||||
#endif // CGAL_CDT_3_DEBUG_CONFORMING
|
||||
return {result_point, reference_vertex->cell(), reference_vertex};
|
||||
}
|
||||
|
||||
protected:
|
||||
T_3& tr() { return *this; };
|
||||
const T_3& tr() const { return *this; };
|
||||
|
||||
Compare_vertex_handle comp = {this};
|
||||
Constraint_hierarchy constraint_hierarchy = {comp};
|
||||
static_assert(CGAL::cdt_3_msvc_2019_or_older() || CGAL::is_nothrow_movable_v<Constraint_hierarchy>);
|
||||
Bbox_3 bbox{};
|
||||
double segment_vertex_epsilon = 1e-8;
|
||||
std::optional<double> max_bbox_edge_length;
|
||||
using Pair_of_vertex_handles = std::pair<Vertex_handle, Vertex_handle>;
|
||||
boost::container::map<Pair_of_vertex_handles, Constrained_polyline_id> pair_of_vertices_to_cid;
|
||||
Insert_in_conflict_visitor insert_in_conflict_visitor = {this};
|
||||
|
||||
using Stack_info = std::pair<Subconstraint, Constrained_polyline_id>;
|
||||
using Subconstraints_to_conform = std::stack<Stack_info, std::vector<Stack_info>>;
|
||||
Subconstraints_to_conform subconstraints_to_conform;
|
||||
|
||||
std::vector<CGAL::unordered_flat_set<Vertex_handle>> all_finite_edges;
|
||||
bool update_all_finite_edges_ = false;
|
||||
|
||||
void update_all_finite_edges() {
|
||||
if(!update_all_finite_edges_) {
|
||||
update_all_finite_edges_ = true;
|
||||
if(use_finite_edges_map()) {
|
||||
all_finite_edges.clear();
|
||||
all_finite_edges.resize(tr().number_of_vertices()+1);
|
||||
for(auto e: tr().all_edges()) {
|
||||
new_edge(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void new_vertex(Vertex_handle v) {
|
||||
if(use_finite_edges_map() && v->time_stamp() >= all_finite_edges.size()) {
|
||||
all_finite_edges.emplace_back();
|
||||
CGAL_assertion(v->time_stamp() == all_finite_edges.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enum class Debug_flags {
|
||||
Steiner_points = 0,
|
||||
conforming,
|
||||
input_faces,
|
||||
missing_region,
|
||||
regions,
|
||||
copy_triangulation_into_hole,
|
||||
validity,
|
||||
use_older_cavity_algorithm,
|
||||
debug_finite_edges_map,
|
||||
use_finite_edges_map,
|
||||
nb_of_flags
|
||||
};
|
||||
std::bitset<static_cast<int>(Debug_flags::nb_of_flags)> debug_flags{};
|
||||
bool is_Delaunay = true;
|
||||
};
|
||||
|
||||
} // end CGAL
|
||||
|
||||
#endif // not DOXYGEN_RUNNING
|
||||
|
||||
#
|
||||
|
||||
#endif // CGAL_CONFORMING_DELAUNAY_TRIANGULATION_3_H
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2025 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CONFORMING_CONSTRAINED_DELAUNAY_TRIANGULATION_3_FWD_H
|
||||
#define CGAL_CONFORMING_CONSTRAINED_DELAUNAY_TRIANGULATION_3_FWD_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <typename Traits, typename Tr>
|
||||
class Conforming_constrained_Delaunay_triangulation_3;
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CONFORMING_CONSTRAINED_DELAUNAY_TRIANGULATION_3_FWD_H
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_BASE_3_H
|
||||
#define CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_BASE_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Triangulation_simplex_base_with_time_stamp.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_cell_data_3.h>
|
||||
#include <CGAL/Triangulation_cell_base_3.h>
|
||||
#include <CGAL/SMDS_3/io_signature.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/**
|
||||
* @ingroup PkgConstrainedTriangulation3Classes
|
||||
* @brief Cell base class for the 3D conforming constrained Delaunay triangulation.
|
||||
*
|
||||
* This class is derived from its template parameter `CellBase` and provides additional functionality
|
||||
* required by `Conforming_constrained_Delaunay_triangulation_3`.
|
||||
*
|
||||
* @tparam Traits The geometric traits class, which must be a model of `ConformingConstrainedDelaunayTriangulationTraits_3`.
|
||||
* It should be the same as the geometric traits class of the triangulation.
|
||||
* @tparam CellBase The base class for the cell, which must be a model of `TriangulationCellBase_3`.
|
||||
*
|
||||
* @cgalModels{ConformingConstrainedDelaunayTriangulationCellBase_3}
|
||||
*
|
||||
* \sa `CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3`
|
||||
*/
|
||||
template <typename Traits, typename CellBase = Triangulation_cell_base_3<Traits> >
|
||||
class Conforming_constrained_Delaunay_triangulation_cell_base_3
|
||||
: public Triangulation_simplex_base_with_time_stamp<CellBase>
|
||||
{
|
||||
using Base = Triangulation_simplex_base_with_time_stamp<CellBase>;
|
||||
Conforming_constrained_Delaunay_triangulation_cell_data_3 ccdt_3_data_;
|
||||
|
||||
public:
|
||||
// To get correct cell type in TDS
|
||||
template < class TDS3 >
|
||||
struct Rebind_TDS {
|
||||
typedef typename CellBase::template Rebind_TDS<TDS3>::Other Cb3;
|
||||
typedef Conforming_constrained_Delaunay_triangulation_cell_base_3 <Traits, Cb3> Other;
|
||||
};
|
||||
|
||||
// Constructors inherited from the base class
|
||||
using Base::Base;
|
||||
|
||||
Conforming_constrained_Delaunay_triangulation_cell_data_3& ccdt_3_data() {
|
||||
return ccdt_3_data_;
|
||||
}
|
||||
|
||||
const Conforming_constrained_Delaunay_triangulation_cell_data_3& ccdt_3_data() const {
|
||||
return ccdt_3_data_;
|
||||
}
|
||||
|
||||
static std::string io_signature() {
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(std::declval<Conforming_constrained_Delaunay_triangulation_cell_data_3>().face_constraint_index(0)), int>);
|
||||
|
||||
return Get_io_signature<Base>()() + "+(" + Get_io_signature<int>()() + ")[4]";
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
const Conforming_constrained_Delaunay_triangulation_cell_base_3& c)
|
||||
{
|
||||
os << static_cast<const Base&>(c);
|
||||
for( unsigned li = 0; li < 4; ++li ) {
|
||||
if(IO::is_ascii(os)) {
|
||||
os << " " << c.ccdt_3_data().face_constraint_index(li);
|
||||
} else {
|
||||
CGAL::write(os, c.ccdt_3_data().face_constraint_index(li));
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
friend std::istream&
|
||||
operator>>(std::istream& is,
|
||||
Conforming_constrained_Delaunay_triangulation_cell_base_3& c)
|
||||
{
|
||||
is >> static_cast<Base&>(c);
|
||||
if(!is) return is;
|
||||
for( int li = 0; li < 4; ++li ) {
|
||||
int i;
|
||||
if(IO::is_ascii(is)) {
|
||||
is >> i;
|
||||
} else {
|
||||
CGAL::read(is, i);
|
||||
}
|
||||
if(!is) return is;
|
||||
c.face_id[li] = i;
|
||||
}
|
||||
return is;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_BASE_3_H
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_DATA_3_H
|
||||
#define CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_DATA_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Constrained_triangulation_3/internal/config.h>
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
|
||||
namespace CGAL {
|
||||
enum class CDT_3_cell_marker {
|
||||
CLEAR = 0,
|
||||
IN_REGION = 1,
|
||||
VISITED = 1,
|
||||
ON_REGION_BOUNDARY = 2,
|
||||
nb_of_markers
|
||||
};
|
||||
|
||||
/*!
|
||||
* @ingroup PkgConstrainedTriangulation3Classes
|
||||
* @brief Internal per-cell data for \cgal 3D conforming constrained Delaunay triangulations
|
||||
*
|
||||
* This class is an internal detail of the implementation of \cgal 3D conforming constrained Delaunay triangulations.
|
||||
*
|
||||
* Any model of the `ConformingConstrainedDelaunayTriangulationCellBase_3` concept must include one object of this type
|
||||
* as a non-static data member.
|
||||
*/
|
||||
class Conforming_constrained_Delaunay_triangulation_cell_data_3 {
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
template <typename Tr> friend class Conforming_constrained_Delaunay_triangulation_3_impl;
|
||||
/// @endcond
|
||||
|
||||
std::array<CDT_3_signed_index, 4> face_id = { -1, -1, -1, -1 };
|
||||
std::array<void*, 4> facet_2d = {nullptr, nullptr, nullptr, nullptr};
|
||||
std::bitset<static_cast<unsigned>(CDT_3_cell_marker::nb_of_markers)> markers;
|
||||
|
||||
bool is_marked() const { return markers.any(); }
|
||||
bool is_marked(CDT_3_cell_marker m) const { return markers.test(static_cast<unsigned>(m)); }
|
||||
void set_mark(CDT_3_cell_marker m) { markers.set(static_cast<unsigned>(m)); }
|
||||
void clear_mark(CDT_3_cell_marker m) { markers.reset(static_cast<unsigned>(m)); }
|
||||
void clear_marks() { markers.reset(); }
|
||||
|
||||
template <typename Facet_handle>
|
||||
void set_facet_constraint(int i, CDT_3_signed_index face_id,
|
||||
Facet_handle facet_2d)
|
||||
{
|
||||
this->face_id[unsigned(i)] = face_id;
|
||||
this->facet_2d[unsigned(i)] = static_cast<void*>(facet_2d == Facet_handle{} ? nullptr : std::addressof(*facet_2d));
|
||||
}
|
||||
|
||||
template <typename CDT_2>
|
||||
auto face_2 (const CDT_2& cdt, int i) const {
|
||||
using Face = typename CDT_2::Face;
|
||||
auto ptr = static_cast<Face*>(facet_2d[unsigned(i)]);
|
||||
return cdt.tds().faces().iterator_to(*ptr);
|
||||
}
|
||||
public:
|
||||
/// @{
|
||||
// @cond SKIP_IN_MANUAL
|
||||
bool is_facet_constrained(int i) const { return face_id[unsigned(i)] >= 0; }
|
||||
|
||||
CDT_3_signed_index face_constraint_index(int i) const {
|
||||
return face_id[unsigned(i)];
|
||||
}
|
||||
|
||||
void set_face_constraint_index(int i, CDT_3_signed_index index) {
|
||||
face_id[unsigned(i)] = index;
|
||||
}
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_CELL_DATA_3_H
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
|
||||
#ifndef CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_BASE_3_H
|
||||
#define CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_BASE_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Triangulation_simplex_base_with_time_stamp.h>
|
||||
#include <CGAL/Triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_data_3.h>
|
||||
#include <CGAL/SMDS_3/io_signature.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/**
|
||||
* @ingroup PkgConstrainedTriangulation3Classes
|
||||
* @brief Vertex base class for the 3D conforming constrained Delaunay triangulation.
|
||||
*
|
||||
* This class is derived from its parameter template `VertexBase` and provides additional functionality
|
||||
* required by `Conforming_constrained_Delaunay_triangulation_3`.
|
||||
*
|
||||
* @tparam Traits The geometric traits class, model of `ConformingConstrainedDelaunayTriangulationTraits_3`.
|
||||
* It must be the same as the geometric traits class of the triangulation.
|
||||
* @tparam VertexBase The base class for the vertex. It must be a model of `TriangulationVertexBase_3`.
|
||||
*
|
||||
* @cgalModels{ConformingConstrainedDelaunayTriangulationVertexBase_3}
|
||||
*
|
||||
* \sa `CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3`
|
||||
*/
|
||||
template < typename Traits, typename VertexBase = Triangulation_vertex_base_3<Traits> >
|
||||
class Conforming_constrained_Delaunay_triangulation_vertex_base_3
|
||||
: public Triangulation_simplex_base_with_time_stamp<VertexBase>
|
||||
{
|
||||
Conforming_constrained_Delaunay_triangulation_vertex_data_3 ccdt_3_data_;
|
||||
|
||||
public:
|
||||
// To get correct vertex type in TDS
|
||||
template <class TDS3> struct Rebind_TDS
|
||||
{
|
||||
using Vb3 = typename VertexBase::template Rebind_TDS<TDS3>::Other;
|
||||
using Other = Conforming_constrained_Delaunay_triangulation_vertex_base_3<Traits, Vb3>;
|
||||
};
|
||||
|
||||
// constructors, inherited from the base class
|
||||
using Base = Triangulation_simplex_base_with_time_stamp<VertexBase>;
|
||||
using Base::Base;
|
||||
|
||||
// model of ConformingConstrainedDelaunayTriangulationVertexBase_3
|
||||
Conforming_constrained_Delaunay_triangulation_vertex_data_3& ccdt_3_data() { return ccdt_3_data_; }
|
||||
const Conforming_constrained_Delaunay_triangulation_vertex_data_3& ccdt_3_data() const { return ccdt_3_data_; }
|
||||
|
||||
static std::string io_signature() {
|
||||
return Get_io_signature<VertexBase>()();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_BASE_3_H
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_DATA_3_H
|
||||
#define CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_DATA_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Constrained_triangulation_3/internal/config.h>
|
||||
|
||||
#include <bitset>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
/*!
|
||||
* @ingroup PkgConstrainedTriangulation3Classes
|
||||
* @brief Internal per-vertex data for \cgal 3D conforming constrained Delaunay triangulations
|
||||
*
|
||||
* This class is an internal detail of the implementation of \cgal 3D conforming constrained Delaunay triangulations.
|
||||
*
|
||||
* Any model of the `ConformingConstrainedDelaunayTriangulationVertexBase_3` concept must include one object of this type
|
||||
* as a non-static data member.
|
||||
*/
|
||||
struct Conforming_constrained_Delaunay_triangulation_vertex_data_3 {};
|
||||
#else // DOXYGEN_RUNNING
|
||||
|
||||
enum class CDT_3_vertex_type { FREE, CORNER, STEINER_ON_EDGE, STEINER_IN_FACE };
|
||||
|
||||
enum class CDT_3_vertex_marker {
|
||||
CLEAR = 0,
|
||||
REGION_BORDER,
|
||||
REGION_INSIDE,
|
||||
CAVITY,
|
||||
CAVITY_ABOVE,
|
||||
CAVITY_BELOW,
|
||||
nb_of_markers
|
||||
};
|
||||
|
||||
class Conforming_constrained_Delaunay_triangulation_vertex_data_3 {
|
||||
protected:
|
||||
// TODO: check and improve the compactness of this class
|
||||
CDT_3_vertex_type m_vertex_type = CDT_3_vertex_type::FREE;
|
||||
std::bitset<static_cast<int>(CDT_3_vertex_marker::nb_of_markers)> mark{};
|
||||
struct C_id {
|
||||
void* ptr = nullptr;
|
||||
std::size_t id = 0;
|
||||
friend bool operator==(const C_id& lhs, const C_id& rhs) {
|
||||
return lhs.ptr == rhs.ptr && lhs.id == rhs.id;
|
||||
}
|
||||
};
|
||||
union U {
|
||||
struct On_edge {
|
||||
int nb_of_incident_constraints = 0;
|
||||
C_id c_id{};
|
||||
} on_edge;
|
||||
struct On_face{
|
||||
CDT_3_signed_index face_index = 0;
|
||||
} on_face;
|
||||
} u {U::On_edge{}};
|
||||
|
||||
public:
|
||||
friend bool operator==(const Conforming_constrained_Delaunay_triangulation_vertex_data_3& lhs,
|
||||
const Conforming_constrained_Delaunay_triangulation_vertex_data_3& rhs) {
|
||||
if(lhs.m_vertex_type != rhs.m_vertex_type || lhs.mark != rhs.mark) return false;
|
||||
switch(lhs.m_vertex_type) {
|
||||
case CDT_3_vertex_type::STEINER_ON_EDGE:
|
||||
return lhs.u.on_edge.nb_of_incident_constraints == rhs.u.on_edge.nb_of_incident_constraints &&
|
||||
lhs.u.on_edge.c_id == rhs.u.on_edge.c_id;
|
||||
case CDT_3_vertex_type::STEINER_IN_FACE:
|
||||
return lhs.u.on_face.face_index == rhs.u.on_face.face_index;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_on_constraint(T constrained_polyline_id) {
|
||||
++u.on_edge.nb_of_incident_constraints;
|
||||
u.on_edge.c_id.ptr = constrained_polyline_id.vl_with_info_pointer();
|
||||
u.on_edge.c_id.id = static_cast<std::size_t>(constrained_polyline_id.index());
|
||||
}
|
||||
|
||||
int number_of_incident_constraints() const {
|
||||
CGAL_assertion(u.on_edge.nb_of_incident_constraints >= 0);
|
||||
return u.on_edge.nb_of_incident_constraints;
|
||||
}
|
||||
|
||||
void set_mark(CDT_3_vertex_marker marker) {
|
||||
mark.set(static_cast<unsigned int>(marker));
|
||||
}
|
||||
|
||||
void clear_marks() {
|
||||
mark.reset();
|
||||
}
|
||||
|
||||
void clear_mark(CDT_3_vertex_marker marker) {
|
||||
mark.reset(static_cast<unsigned int>(marker));
|
||||
}
|
||||
|
||||
bool is_marked(CDT_3_vertex_marker marker) const {
|
||||
return mark.test(static_cast<unsigned int>(marker));
|
||||
}
|
||||
|
||||
bool is_marked() const {
|
||||
return mark.any();
|
||||
}
|
||||
|
||||
template<typename Triangulation>
|
||||
auto constrained_polyline_id(const Triangulation&) const {
|
||||
CGAL_assertion(m_vertex_type != CDT_3_vertex_type::STEINER_IN_FACE);
|
||||
using C_id = typename Triangulation::Constrained_polyline_id;
|
||||
using size_type = typename Triangulation::size_type;
|
||||
using Vertex_list_w_info_ptr = decltype(std::declval<C_id>().vl_with_info_pointer());
|
||||
auto ptr = static_cast<Vertex_list_w_info_ptr>(u.on_edge.c_id.ptr);
|
||||
auto id = static_cast<size_type>(u.on_edge.c_id.id);
|
||||
return C_id{ptr, id};
|
||||
}
|
||||
|
||||
void set_Steiner_vertex_in_face(CDT_3_signed_index face_index) {
|
||||
m_vertex_type = CDT_3_vertex_type::STEINER_IN_FACE;
|
||||
u.on_face = typename U::On_face{face_index};
|
||||
}
|
||||
|
||||
CDT_3_signed_index face_index() const {
|
||||
CGAL_assertion(m_vertex_type == CDT_3_vertex_type::STEINER_IN_FACE);
|
||||
return u.on_face.face_index;
|
||||
}
|
||||
|
||||
CDT_3_vertex_type vertex_type() const { return m_vertex_type; }
|
||||
void set_vertex_type(CDT_3_vertex_type type) { m_vertex_type = type; }
|
||||
bool is_Steiner_vertex_on_edge() const { return m_vertex_type == CDT_3_vertex_type::STEINER_ON_EDGE; }
|
||||
bool is_Steiner_vertex_in_face() const { return m_vertex_type == CDT_3_vertex_type::STEINER_IN_FACE; }
|
||||
};
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#if CGAL_CXX20 && __cpp_concepts >= 201911L
|
||||
# include <concepts>
|
||||
|
||||
static_assert(std::regular<CGAL::Conforming_constrained_Delaunay_triangulation_vertex_data_3>);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CGAL_CONSTRAINED_DELAUNAY_TRIANGULATION_VERTEX_DATA_3_H
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2023-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CDT_3_DEBUG_IO_H
|
||||
#define CGAL_CDT_3_DEBUG_IO_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/IO/polygon_soup_io.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <typename Tr, typename Facets>
|
||||
auto export_facets_to_surface_mesh(const Tr& tr, Facets&& facets_range) {
|
||||
using Point_3 = typename Tr::Geom_traits::Point_3;
|
||||
const auto size = std::distance(facets_range.begin(), facets_range.end());
|
||||
std::vector<Point_3> points;
|
||||
points.reserve(size * 3);
|
||||
std::vector<std::array<std::size_t, 3>> facets;
|
||||
facets.reserve(size);
|
||||
|
||||
std::size_t i = 0;
|
||||
for(const auto& [cell, facet_index] : facets_range) {
|
||||
const auto v0 = cell->vertex(Tr::vertex_triple_index(facet_index, 0));
|
||||
const auto v1 = cell->vertex(Tr::vertex_triple_index(facet_index, 1));
|
||||
const auto v2 = cell->vertex(Tr::vertex_triple_index(facet_index, 2));
|
||||
points.push_back(tr.point(v0));
|
||||
points.push_back(tr.point(v1));
|
||||
points.push_back(tr.point(v2));
|
||||
facets.push_back({i, i+1, i+2});
|
||||
i += 3;
|
||||
}
|
||||
CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup(points, facets);
|
||||
CGAL::Polygon_mesh_processing::orient_polygon_soup(points, facets);
|
||||
Surface_mesh<Point_3> mesh;
|
||||
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, facets, mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
template <typename Tr, typename Facets>
|
||||
void write_facets(std::ostream& out, const Tr& tr, Facets&& facets_range) {
|
||||
const auto mesh = export_facets_to_surface_mesh(tr, std::forward<Facets>(facets_range));
|
||||
CGAL::IO::write_OFF(out, mesh);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CGAL_CDT_3_DEBUG_IO_H
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2019-2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CDT_3_CONFIG_H
|
||||
#define CGAL_CDT_3_CONFIG_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/config.h>
|
||||
|
||||
#include <CGAL/Constrained_triangulation_3_types.h>
|
||||
|
||||
#if CGAL_CAN_USE_CXX20_FORMAT
|
||||
# define CGAL_CDT_3_CAN_USE_CXX20_FORMAT 1
|
||||
# include <format>
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
constexpr bool cdt_3_msvc_2019_or_older() {
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1930)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CGAL_CDT_3_CAN_USE_CXX20_FORMAT
|
||||
|
||||
constexpr bool cdt_3_can_use_cxx20_format() {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
decltype(auto) cdt_3_format(std::string_view fmt, const Args&... args) {
|
||||
return std::vformat(fmt, std::make_format_args(args...));
|
||||
}
|
||||
|
||||
#else // not CGAL_CDT_3_CAN_USE_CXX20_FORMAT
|
||||
|
||||
template <typename... Args>
|
||||
constexpr decltype(auto) cdt_3_format(Args&&...) {
|
||||
return "";
|
||||
}
|
||||
|
||||
constexpr bool cdt_3_can_use_cxx20_format() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // not CGAL_CDT_3_CAN_USE_CXX20_FORMAT
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CDT_3_CONFIG_H
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2025 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CDT_3_INTERNAL_OSTREAM_REDIRECT_GUARD_H
|
||||
#define CGAL_CDT_3_INTERNAL_OSTREAM_REDIRECT_GUARD_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace CGAL {
|
||||
namespace internal {
|
||||
|
||||
class ostream_redirect_guard {
|
||||
public:
|
||||
// Builder for fluent API
|
||||
class builder {
|
||||
public:
|
||||
explicit builder(std::ostream& target) : target_(target) {}
|
||||
ostream_redirect_guard to(std::ostream& redirect_to) {
|
||||
return ostream_redirect_guard(target_, redirect_to);
|
||||
}
|
||||
private:
|
||||
std::ostream& target_;
|
||||
};
|
||||
|
||||
static builder redirect(std::ostream& target) {
|
||||
return builder(target);
|
||||
}
|
||||
|
||||
ostream_redirect_guard(const ostream_redirect_guard&) = delete;
|
||||
ostream_redirect_guard& operator=(const ostream_redirect_guard&) = delete;
|
||||
|
||||
~ostream_redirect_guard() { restore(); }
|
||||
|
||||
ostream_redirect_guard(ostream_redirect_guard&& other) noexcept
|
||||
: target_(other.target_), old_buf_(other.old_buf_) {
|
||||
other.old_buf_ = nullptr;
|
||||
}
|
||||
private:
|
||||
friend class builder;
|
||||
ostream_redirect_guard(std::ostream& target, std::ostream& redirect_to)
|
||||
: target_(target), old_buf_(target.rdbuf(redirect_to.rdbuf())) {}
|
||||
|
||||
void restore() {
|
||||
if (old_buf_) target_.rdbuf(old_buf_);
|
||||
old_buf_ = nullptr;
|
||||
}
|
||||
|
||||
std::ostream& target_;
|
||||
std::streambuf* old_buf_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CDT_3_INTERNAL_OSTREAM_REDIRECT_GUARD_H
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2023-2025 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CDT_3_INTERNAL_READ_POLYGON_MESH_FOR_CDT_3_H
|
||||
#define CGAL_CDT_3_INTERNAL_READ_POLYGON_MESH_FOR_CDT_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Constrained_triangulation_3/internal/cdt_debug_io.h>
|
||||
#include <CGAL/Constrained_triangulation_3/internal/ostream_redirect_guard.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h>
|
||||
#include <tl/expected.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template <typename PolygonMesh>
|
||||
struct CDT_3_read_polygon_mesh_output {
|
||||
tl::expected<PolygonMesh, std::string> polygon_mesh;
|
||||
|
||||
std::size_t nb_of_duplicated_points = 0;
|
||||
std::size_t nb_of_simplified_polygons = 0;
|
||||
std::size_t nb_of_new_polygons = 0;
|
||||
std::size_t nb_of_removed_invalid_polygons = 0;
|
||||
std::size_t nb_of_removed_duplicated_polygons = 0;
|
||||
std::size_t nb_of_removed_isolated_points = 0;
|
||||
|
||||
bool polygon_soup_self_intersects = false;
|
||||
bool polygon_mesh_is_manifold = true;
|
||||
};
|
||||
|
||||
template <typename PolygonMesh,
|
||||
typename Points,
|
||||
typename Faces,
|
||||
typename NamedParameters = parameters::Default_named_parameters>
|
||||
CDT_3_read_polygon_mesh_output<PolygonMesh> convert_polygon_soup_to_polygon_mesh_for_cdt_3(
|
||||
Points& points, Faces& faces, const NamedParameters& np = parameters::default_values())
|
||||
{
|
||||
CDT_3_read_polygon_mesh_output<PolygonMesh> result;
|
||||
using Traits = typename GetPolygonGeomTraits<Points, Faces, NamedParameters>::type;
|
||||
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
auto traits = choose_parameter<Traits>(get_parameter(np, internal_np::geom_traits));
|
||||
auto verbose = choose_parameter(get_parameter(np, internal_np::verbose), false);
|
||||
bool do_repair = choose_parameter(get_parameter(np, internal_np::repair_polygon_soup), true);
|
||||
const auto& return_error = parameters::get_parameter_reference(np, internal_np::callback);
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace PMP_internal = PMP::internal;
|
||||
|
||||
if (do_repair)
|
||||
{
|
||||
result.nb_of_duplicated_points = PMP::merge_duplicate_points_in_polygon_soup(points, faces, np);
|
||||
result.nb_of_simplified_polygons = PMP_internal::simplify_polygons_in_polygon_soup(points, faces, traits);
|
||||
result.nb_of_new_polygons = PMP_internal::split_pinched_polygons_in_polygon_soup(points, faces, traits);
|
||||
result.nb_of_removed_invalid_polygons = PMP_internal::remove_invalid_polygons_in_polygon_soup(points, faces);
|
||||
result.nb_of_removed_duplicated_polygons = PMP::merge_duplicate_polygons_in_polygon_soup(points, faces, np);
|
||||
result.nb_of_removed_isolated_points = PMP::remove_isolated_points_in_polygon_soup(points, faces);
|
||||
}
|
||||
|
||||
result.polygon_soup_self_intersects = PMP::does_polygon_soup_self_intersect(points, faces, np);
|
||||
|
||||
if (!PMP::orient_polygon_soup(points, faces))
|
||||
{
|
||||
result.polygon_mesh_is_manifold = false;
|
||||
if (verbose)
|
||||
std::cerr << "Some duplication happened during polygon soup orientation" << std::endl;
|
||||
}
|
||||
|
||||
if (!PMP::is_polygon_soup_a_polygon_mesh(faces))
|
||||
{
|
||||
if (verbose)
|
||||
std::cerr << "Warning: polygon soup does not describe a polygon mesh" << std::endl;
|
||||
if constexpr (std::is_invocable_v<decltype(return_error)>)
|
||||
return return_error();
|
||||
else
|
||||
return result;
|
||||
}
|
||||
PMP::polygon_soup_to_polygon_mesh(points, faces, *result.polygon_mesh, parameters::default_values(), np);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename PolygonMesh, typename NamedParameters = parameters::Default_named_parameters>
|
||||
CDT_3_read_polygon_mesh_output<PolygonMesh>
|
||||
read_polygon_mesh_for_cdt_3(const std::string &fname,
|
||||
const NamedParameters &np = parameters::default_values())
|
||||
{
|
||||
CDT_3_read_polygon_mesh_output<PolygonMesh> result;
|
||||
|
||||
using VPM = typename CGAL::GetVertexPointMap<PolygonMesh, NamedParameters>::type;
|
||||
using Point = typename boost::property_traits<VPM>::value_type;
|
||||
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
auto verbose = choose_parameter(get_parameter(np, internal_np::verbose), false);
|
||||
|
||||
std::ostringstream local_verbose_output;
|
||||
{
|
||||
auto cerr_redirect = CGAL::internal::ostream_redirect_guard::redirect(std::cerr).to(local_verbose_output);
|
||||
|
||||
auto return_error = [&]() {
|
||||
result.polygon_mesh = tl::unexpected(std::move(local_verbose_output).str());
|
||||
return result;
|
||||
};
|
||||
|
||||
using Points = std::vector<Point>;
|
||||
using Face = std::vector<std::size_t>;
|
||||
using Faces = std::vector<Face>;
|
||||
Points points;
|
||||
Faces faces;
|
||||
if(!CGAL::IO::read_polygon_soup(fname, points, faces, CGAL::parameters::verbose(true))) {
|
||||
if(verbose)
|
||||
std::cerr << "Warning: cannot read polygon soup" << std::endl;
|
||||
return return_error();
|
||||
}
|
||||
result = convert_polygon_soup_to_polygon_mesh_for_cdt_3<PolygonMesh>(points, faces, np.callback(return_error));
|
||||
}
|
||||
if(verbose) {
|
||||
std::cerr << std::move(local_verbose_output).str();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // end namespace CGAL
|
||||
|
||||
#endif // CGAL_CDT_3_INTERNAL_READ_POLYGON_MESH_FOR_CDT_3_H
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_CT_3_TYPES_H
|
||||
#define CGAL_CT_3_TYPES_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/config.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/**
|
||||
* @ingroup PkgConstrainedTriangulation3Classes
|
||||
* \brief Signed integral type to store the index of constraints.
|
||||
*/
|
||||
using CDT_3_signed_index = int; // must be signed
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CT_3_TYPES_H
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) 2019-2024 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) : Jane Tournois
|
||||
|
||||
#include "CGAL/type_traits.h"
|
||||
#include "CGAL/unordered_flat_map.h"
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Named_function_parameters.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
||||
#include <CGAL/IO/File_medit.h>
|
||||
#include <ostream>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
/*!
|
||||
* @ingroup PkgCDT3IOFunctions
|
||||
* @brief outputs a conforming constrained Delaunay triangulation to
|
||||
* the MEDIT (`.mesh`) file format.
|
||||
* See \cgalCite{frey:inria-00069921} for a comprehensive description of this
|
||||
* file format.
|
||||
* @param os the output stream
|
||||
* @param ccdt the conforming constrained Delaunay triangulation to be written
|
||||
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamNBegin{with_plc_face_id}
|
||||
* \cgalParamDescription{a Boolean activating the numbering of PLC face identifiers in the output.
|
||||
* If `ccdt` was constructed with the `plc_face_id` property map given as a named parameter,
|
||||
* and this parameter is set to `true`,
|
||||
* the output will contain the corresponding patch identifier for each facet of the triangulation.
|
||||
* If this parameter is set to `false`, the output will not contain any patch identifier.
|
||||
* If `ccdt` was not constructed with the `plc_face_id` property map, and this parameter is
|
||||
* set to `true`, the output will contain a patch identifier for each facet of the triangulation.}
|
||||
* \cgalParamType{Boolean}
|
||||
* \cgalParamDefault{`false`}
|
||||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
|
||||
* \see \ref IOStreamMedit
|
||||
*/
|
||||
template <typename Traits,
|
||||
typename Tr,
|
||||
typename NamedParameters = parameters::Default_named_parameters>
|
||||
void write_MEDIT(std::ostream& os,
|
||||
const Conforming_constrained_Delaunay_triangulation_3<Traits, Tr>& ccdt,
|
||||
const NamedParameters& np = parameters::default_values())
|
||||
{
|
||||
const auto& tr = ccdt.triangulation();
|
||||
|
||||
using Tr_ = typename cpp20::remove_cvref_t<decltype(tr)>;
|
||||
|
||||
using Vertex_handle = typename Tr_::Vertex_handle;
|
||||
using Facet = typename Tr_::Facet;
|
||||
using Cell_handle = typename Tr_::Cell_handle;
|
||||
CGAL::unordered_flat_map<Cell_handle, bool> cells_in_domain;
|
||||
for(Cell_handle c : tr.all_cell_handles())
|
||||
cells_in_domain[c] = true;
|
||||
|
||||
std::stack<Cell_handle> stack;
|
||||
stack.push(tr.infinite_cell());
|
||||
while(!stack.empty())
|
||||
{
|
||||
auto ch = stack.top();
|
||||
stack.pop();
|
||||
cells_in_domain[ch] = false;
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
if(ccdt.is_facet_constrained(ch, i))
|
||||
continue;
|
||||
auto n = ch->neighbor(i);
|
||||
if(cells_in_domain[n])
|
||||
stack.push(n);
|
||||
}
|
||||
}
|
||||
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
const bool has_plc_face_id
|
||||
= choose_parameter(get_parameter(np, internal_np::with_plc_face_id), false);
|
||||
|
||||
auto plc_patch_map = boost::make_function_property_map<Facet>([&](const Facet& f)
|
||||
{ return has_plc_face_id ? f.first->ccdt_3_data().face_constraint_index(f.second) + 1 : 1; });
|
||||
|
||||
return SMDS_3::output_to_medit(os,
|
||||
tr,
|
||||
tr.finite_vertex_handles(),
|
||||
ccdt.constrained_facets(),
|
||||
tr.finite_cell_handles(),
|
||||
boost::make_function_property_map<Vertex_handle>([](Vertex_handle) { return 0; }),
|
||||
plc_patch_map,
|
||||
boost::make_function_property_map<Cell_handle>([&](Cell_handle ch) {
|
||||
return cells_in_domain[ch] ? 1 : 0;
|
||||
}));
|
||||
}
|
||||
|
||||
}// end namespace IO
|
||||
}// end namespace CGAL
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 2025 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_DRAW_CONSTRAINED_T3_H
|
||||
#define CGAL_DRAW_CONSTRAINED_T3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
#include <CGAL/draw_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3_fwd.h>
|
||||
#include <CGAL/type_traits.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace CGAL {
|
||||
/*!
|
||||
\ingroup PkgDrawCDT_3
|
||||
|
||||
opens a new `CGAL::Qt::Basic_viewer` window and draws the constrained triangulation.
|
||||
|
||||
A call to this function blocks the execution of the program until the drawing window is closed. This function requires `CGAL_Qt6`,
|
||||
and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined.
|
||||
Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt6` and add the definition `CGAL_USE_BASIC_VIEWER`.
|
||||
*/
|
||||
template <typename Traits, typename Tr>
|
||||
void draw(const Conforming_constrained_Delaunay_triangulation_3<Traits, Tr>& ccdt,
|
||||
const char *title="3D Constrained Triangulation")
|
||||
{
|
||||
using Tr_ = CGAL::cpp20::remove_cvref_t<decltype(ccdt.triangulation())>;
|
||||
using Vertex_handle = typename Tr_::Vertex_handle;
|
||||
using Cell_handle = typename Tr_::Cell_handle;
|
||||
using Edge_descriptor = typename Tr_::Finite_edges_iterator;
|
||||
using Facet_descriptor = typename Tr_::Finite_facets_iterator;
|
||||
|
||||
using Face_index = CGAL::cpp20::remove_cvref_t<
|
||||
decltype(std::declval<Cell_handle>()->ccdt_3_data().face_constraint_index(0))>;
|
||||
|
||||
Face_index nb_colors = 0;
|
||||
std::for_each(
|
||||
ccdt.constrained_facets_begin(), ccdt.constrained_facets_end(),
|
||||
[&](const auto& f) {
|
||||
auto [c, index] = f;
|
||||
nb_colors = (std::max)(nb_colors, c->ccdt_3_data().face_constraint_index(index) + 1);
|
||||
});
|
||||
std::vector<CGAL::IO::Color> colors(nb_colors);
|
||||
std::generate(colors.begin(), colors.end(), []() {
|
||||
return CGAL::get_random_color(CGAL::get_default_random());
|
||||
});
|
||||
CGAL::Graphics_scene_options<Tr_, Vertex_handle, Edge_descriptor, Facet_descriptor> options;
|
||||
options.draw_face = [](const Tr_&, Facet_descriptor f) {
|
||||
auto [c, index] = *f;
|
||||
return c->ccdt_3_data().is_facet_constrained(index);
|
||||
};
|
||||
options.colored_face = [](const Tr_&, Facet_descriptor) {
|
||||
return true;
|
||||
};
|
||||
options.face_color = [&](const Tr_&, Facet_descriptor f) {
|
||||
auto [c, index] = *f;
|
||||
return colors[c->ccdt_3_data().face_constraint_index(index)];
|
||||
};
|
||||
draw(ccdt.triangulation(), options, title);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgDrawCDT_3
|
||||
|
||||
A shortcut to \link PkgDrawTriangulation3 `CGAL::draw(ccdt.triangulation(), gs_options, title)` \endlink.
|
||||
*/
|
||||
template <typename Traits, typename Tr, typename GSOptions>
|
||||
void draw(const Conforming_constrained_Delaunay_triangulation_3<Traits, Tr>& ccdt,
|
||||
const GSOptions& gs_options,
|
||||
const char *title="3D Constrained Triangulation")
|
||||
{
|
||||
draw(ccdt.triangulation(), gs_options, title);
|
||||
}
|
||||
|
||||
} // End namespace CGAL
|
||||
|
||||
#endif // CGAL_DRAW_CONSTRAINED_T3_H
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
// Copyright (c) 2024 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) : Laurent Rineau
|
||||
|
||||
#ifndef CGAL_MAKE_CONSTRAINED_DELAUNAY_TRIANGULATION_3_H
|
||||
#define CGAL_MAKE_CONSTRAINED_DELAUNAY_TRIANGULATION_3_H
|
||||
|
||||
#include <CGAL/license/Constrained_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_cell_base_3.h>
|
||||
#include <CGAL/Triangulation_3.h>
|
||||
#include <CGAL/Triangulation_data_structure_3.h>
|
||||
|
||||
#include <CGAL/Named_function_parameters.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\addtogroup PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh
|
||||
@{
|
||||
|
||||
Free Functions Template for Creating Conforming Constrained Delaunay Triangulations {#PkgConstrainedTriangulation3Functions}
|
||||
==========================================================================
|
||||
|
||||
The following functions create a 3D conforming constrained Delaunay triangulation
|
||||
from either a polygon soup or a polygon mesh.
|
||||
|
||||
Input Data {#make_conforming_constrained_Delaunay_triangulation_3_input_data}
|
||||
----------
|
||||
|
||||
The input data (polygon mesh or polygon soup) represents the polygonal constraints enforced
|
||||
during the triangulation process.
|
||||
|
||||
By default, each face of the input is considered a polygonal constraint for the triangulation. The
|
||||
named parameter `plc_face_id` can be used to describe larger polygonal constraints, possibly with holes. If
|
||||
used, this parameter must be a property map that associates each face of the input with a PLC face
|
||||
identifier. Faces with the same face identifier are considered part of the same surface patch. Each of these
|
||||
surface patches (defined as the union of the input faces with a given patch identifier) is expected to be a polygon or
|
||||
a polygon with holes, with coplanar vertices (or nearly coplanar up to the precision of the number type used).
|
||||
|
||||
The generated triangulation will conform to the faces of the input, or to the surface patches
|
||||
described by the `plc_face_id` property map if provided.
|
||||
|
||||
In the case where the input contains a non-planar PLC face, building the triangulation may fail with an exception
|
||||
of type `CGAL::Non_planar_plc_facet_exception`.
|
||||
|
||||
\pre The input data must not be coplanar.
|
||||
\pre The input data must not have self-intersections.
|
||||
|
||||
Template Parameters {#make_conforming_constrained_Delaunay_triangulation_3_template_parameters}
|
||||
-------------------
|
||||
|
||||
For both function templates, the template arguments can be deduced from the function arguments, or defaulted.
|
||||
|
||||
- The first template argument `Triangulation` defaults to `CGAL::Default`, and in that case the
|
||||
triangulation type is deduced from the input type and the named parameters (see below).
|
||||
- The following one or two template arguments are deduced from the input data: either a polygon mesh type,
|
||||
or a polygon soup defined by two types (a sequence of points and a sequence of sequences of indices).
|
||||
- The last template argument is the named parameters class, deduced from the function arguments.
|
||||
|
||||
|
||||
Returned Triangulation Type {#make_conforming_constrained_Delaunay_triangulation_3_returned_type}
|
||||
---------------------------
|
||||
|
||||
For both functions, the template parameter `Triangulation` defines the type of the triangulation that is created
|
||||
and returned by the function.
|
||||
|
||||
- If `Triangulation` is `CGAL::Default`, the geometric traits class type is deduced from the input data and
|
||||
the named parameters. If the named parameter `geom_traits` is provided, the traits class is deduced from it.
|
||||
Otherwise, the point type of the input data is used to deduce the traits class. Let's call it `Traits`.
|
||||
The returned triangulation type is then `CGAL::Conforming_constrained_Delaunay_triangulation_3<Traits>`.
|
||||
- Otherwise, `Triangulation` must be a specialization of the `CGAL::Conforming_constrained_Delaunay_triangulation_3`
|
||||
class template, with the following requirements:
|
||||
- its `Vertex` type must be a model of `ConformingConstrainedDelaunayTriangulationVertexBase_3`, and
|
||||
- its `Cell` type must be a model of `ConformingConstrainedDelaunayTriangulationCellBase_3`.
|
||||
|
||||
In both cases, the traits class `Traits` must fulfill the following requirements:
|
||||
- It must be a model of the concept `ConformingConstrainedDelaunayTriangulationTraits_3`.
|
||||
- It must have a `Point_3` type that is constructible from the point type of the input data.
|
||||
@}
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \ingroup PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh
|
||||
*
|
||||
* \brief creates a 3D constrained Delaunay triangulation conforming to the faces of a polygon mesh.
|
||||
*
|
||||
* \tparam PolygonMesh a model of `FaceListGraph`
|
||||
* \tparam Triangulation an instance of the `CGAL::Conforming_constrained_Delaunay_triangulation_3` class template,
|
||||
* or `CGAL::Default`
|
||||
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
||||
*
|
||||
* \param mesh the polygon mesh representing the constraints
|
||||
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
*
|
||||
* \cgalParamNBegin{vertex_point_map}
|
||||
* \cgalParamDescription{a property map associating points to the vertices of `mesh`}
|
||||
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%vertex_descriptor`
|
||||
* as key type and `%Traits::Point_3` as value type}
|
||||
* \cgalParamDefault{`boost::get(CGAL::vertex_point, mesh)`}
|
||||
* \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
|
||||
* must be available in `PolygonMesh`.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{plc_face_id}
|
||||
* \cgalParamDescription{a property map associating a patch identifier to each facet of `mesh`.
|
||||
* Each identifier corresponds to a planar surface patch. Each surface
|
||||
* patch can be composed of several facets of `mesh`, forming a planar polygon.}
|
||||
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<PolygonMesh>::%face_descriptor`
|
||||
* as key type and with any value type that is a *regular* type (model of `Regular`)}
|
||||
* \cgalParamExtra{If this parameter is omitted, each facet of `mesh` is considered a separate PLC face.
|
||||
* Faces of `mesh` with the same patch identifier are considered part of the same PLC face.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{geom_traits}
|
||||
* \cgalParamDescription{an instance of a geometric traits class}
|
||||
* \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type}
|
||||
* \cgalParamDefault{the default constructed traits object `Traits{}`}
|
||||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \return a 3D constrained Delaunay triangulation conforming to the faces of the polygon mesh, of a type
|
||||
* described in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type above.
|
||||
*
|
||||
* \pre `mesh` must not have self-intersections.
|
||||
* For triangulated surfaces, it can be checked using the function
|
||||
* \link CGAL::Polygon_mesh_processing::does_self_intersect
|
||||
* `CGAL::Polygon_mesh_processing::does_self_intersect(mesh, np) == false`
|
||||
* \endlink
|
||||
*/
|
||||
template <typename Triangulation = CGAL::Default,
|
||||
typename PolygonMesh,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
auto make_conforming_constrained_Delaunay_triangulation_3(const PolygonMesh &mesh,
|
||||
const CGAL_NP_CLASS &np = parameters::default_values())
|
||||
{
|
||||
using Mesh_geom_traits = typename GetGeomTraits<PolygonMesh, CGAL_NP_CLASS>::type;
|
||||
using CDT = typename CGAL::Default::Get<Triangulation,
|
||||
Conforming_constrained_Delaunay_triangulation_3<Mesh_geom_traits>>::type;
|
||||
CDT cdt(mesh, np);
|
||||
auto remeshing_cdt{std::move(cdt)};
|
||||
static_assert(std::is_same_v<decltype(remeshing_cdt), CDT>);
|
||||
return remeshing_cdt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup PkgConstrainedTriangulation3FunctionsPolygonSoupOrMesh
|
||||
*
|
||||
* \brief creates a 3D constrained Delaunay triangulation conforming to the faces of a polygon soup.
|
||||
*
|
||||
* \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type
|
||||
* of the polygon soup
|
||||
* \tparam PolygonRange a model of the concept `RandomAccessContainer` whose value type is a model of the concept
|
||||
* `RandomAccessContainer` whose value type is `std::size_t`
|
||||
* \tparam Triangulation an instance of the `CGAL::Conforming_constrained_Delaunay_triangulation_3` class template,
|
||||
* or `CGAL::Default`
|
||||
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
|
||||
*
|
||||
* \param points a range of points representing the vertices of the polygon soup
|
||||
* \param polygons a range of ranges of indices representing the faces of the polygon soup
|
||||
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
*
|
||||
* \cgalParamNBegin{point_map}
|
||||
* \cgalParamDescription{a property map associating points to the elements of the range `points`}
|
||||
* \cgalParamType{a model of `ReadablePropertyMap` whose
|
||||
* key type is the value type of `PointRange`, and
|
||||
* value type is convertible to the point type of the geometric traits class}
|
||||
* \cgalParamDefault{`CGAL::Identity_property_map`}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{plc_face_id}
|
||||
* \cgalParamDescription{a property map associating a patch identifier to each facet of `soup`.
|
||||
* Each identifier corresponds to a planar surface patch. Each surface
|
||||
* patch can be composed of several faces of `soup`, forming a planar polygon.}
|
||||
* \cgalParamType{a class model of `ReadablePropertyMap` with `std::size_t`
|
||||
* as key type and with any value type that is a *regular* type (model of `Regular`)}
|
||||
* \cgalParamExtra{If this parameter is omitted, each facet of the polygon soup is considered a separate PLC face.}
|
||||
* \cgalParamExtra{Otherwise facets with the same patch identifier are considered part of the same PLC face.}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalParamNBegin{geom_traits}
|
||||
* \cgalParamDescription{an instance of a geometric traits class}
|
||||
* \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type}
|
||||
* \cgalParamDefault{the default constructed traits object `Traits{}`}
|
||||
* \cgalParamNEnd
|
||||
*
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \return a 3D constrained Delaunay triangulation conforming to the faces of the polygon soup, of a type
|
||||
* described in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type above.
|
||||
*
|
||||
* \pre The polygon soup must be free of self-intersections. If the polygon soup is a triangle soup, this is equivalent to:
|
||||
* \link CGAL::Polygon_mesh_processing::does_triangle_soup_self_intersect
|
||||
* `CGAL::Polygon_mesh_processing::does_triangle_soup_self_intersect(points, polygons, np) == false`
|
||||
* \endlink.
|
||||
*/
|
||||
template <typename Triangulation = CGAL::Default,
|
||||
typename PointRange,
|
||||
typename PolygonRange,
|
||||
typename NamedParameters = parameters::Default_named_parameters>
|
||||
auto make_conforming_constrained_Delaunay_triangulation_3(const PointRange &points,
|
||||
const PolygonRange &polygons,
|
||||
const NamedParameters &np = parameters::default_values())
|
||||
{
|
||||
using Geom_traits = typename GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type;
|
||||
|
||||
using Default_CDT = Conforming_constrained_Delaunay_triangulation_3<Geom_traits>;
|
||||
using CDT = typename CGAL::Default::Get<Triangulation, Default_CDT>::type;
|
||||
CDT cdt(points, polygons, np);
|
||||
auto remeshing_cdt{std::move(cdt)};
|
||||
static_assert(std::is_same_v<decltype(remeshing_cdt), CDT>);
|
||||
return remeshing_cdt;
|
||||
}
|
||||
|
||||
} // end namespace CGAL
|
||||
|
||||
#endif // CGAL_MAKE_CONSTRAINED_DELAUNAY_TRIANGULATION_3_H
|
||||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory (France)
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Algebraic_foundations
|
||||
Arithmetic_kernel
|
||||
BGL
|
||||
Basic_viewer
|
||||
Box_intersection_d
|
||||
CGAL_Core
|
||||
Cartesian_kernel
|
||||
Circulator
|
||||
Constrained_triangulation_3
|
||||
Distance_2
|
||||
Distance_3
|
||||
Filtered_kernel
|
||||
Hash_map
|
||||
Homogeneous_kernel
|
||||
Installation
|
||||
Intersections_2
|
||||
Intersections_3
|
||||
Interval_support
|
||||
Kernel_23
|
||||
Kernel_d
|
||||
Mesh_3
|
||||
Modular_arithmetic
|
||||
Number_types
|
||||
Polygon
|
||||
Polygon_mesh_processing
|
||||
Principal_component_analysis_LGPL
|
||||
Profiling_tools
|
||||
Property_map
|
||||
Random_numbers
|
||||
SMDS_3
|
||||
STL_Extension
|
||||
Solver_interface
|
||||
Spatial_sorting
|
||||
Stream_support
|
||||
Surface_mesh
|
||||
TDS_2
|
||||
TDS_3
|
||||
Triangulation_2
|
||||
Triangulation_3
|
||||
Union_find
|
||||
Weights
|
||||
|
|
@ -0,0 +1 @@
|
|||
3D constrained triangulations
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -0,0 +1 @@
|
|||
Laurent Rineau <laurent.rineau@geometryfactory.com>
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
cmake_minimum_required(VERSION 3.12...3.31)
|
||||
project(Constrained_triangulation_3_Tests)
|
||||
|
||||
find_package(CGAL REQUIRED)
|
||||
|
||||
create_single_source_cgal_program(test_constrained_Delaunay_triangulation_3.cpp)
|
||||
create_single_source_cgal_program(test_2D_constrained_Delaunay_triangulation_3.cpp)
|
||||
create_single_source_cgal_program(test_ccdt_remeshing.cpp)
|
||||
|
||||
find_package(Eigen3 QUIET)
|
||||
include(CGAL_Eigen3_support)
|
||||
|
||||
include(CGAL_setup_tl-excepted)
|
||||
# CDT_3: C++20 for structured bindings
|
||||
add_library(CDT_3_dependencies INTERFACE)
|
||||
target_compile_features(CDT_3_dependencies INTERFACE cxx_std_20)
|
||||
target_link_libraries(CDT_3_dependencies INTERFACE CGAL::CGAL CGAL::Data CGAL::Eigen3_support tl::expected)
|
||||
|
||||
create_single_source_cgal_program( "cdt_test_insert_constrained_edge_from_EDG_file.cpp")
|
||||
target_link_libraries(cdt_test_insert_constrained_edge_from_EDG_file PRIVATE CDT_3_dependencies)
|
||||
create_single_source_cgal_program( "cdt_test_insert_constrained_edge_from_OFF_file.cpp")
|
||||
target_link_libraries(cdt_test_insert_constrained_edge_from_OFF_file PRIVATE CDT_3_dependencies)
|
||||
create_single_source_cgal_program( "cdt_3_from_off.cpp")
|
||||
target_link_libraries(cdt_3_from_off PRIVATE CDT_3_dependencies)
|
||||
create_single_source_cgal_program( "cdt_3_from_off_with_Epeck.cpp")
|
||||
target_link_libraries(cdt_3_from_off_with_Epeck PRIVATE CDT_3_dependencies)
|
||||
create_single_source_cgal_program( "snap_and_cdt3.cpp")
|
||||
|
||||
if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||
add_executable(cdt_3_from_off_CGAL_DEBUG_CDT_3 cdt_3_from_off)
|
||||
target_compile_definitions(cdt_3_from_off_CGAL_DEBUG_CDT_3 PRIVATE CGAL_DEBUG_CDT_3=255)
|
||||
target_link_libraries(cdt_3_from_off_CGAL_DEBUG_CDT_3 PRIVATE CDT_3_dependencies)
|
||||
cgal_add_test(cdt_3_from_off_CGAL_DEBUG_CDT_3)
|
||||
endif()
|
||||
|
||||
add_executable(test_CDT_3_insert_constrained_edge_from_EDG_file cdt_test_insert_constrained_edge_from_EDG_file.cpp)
|
||||
target_link_libraries(test_CDT_3_insert_constrained_edge_from_EDG_file PRIVATE CDT_3_dependencies)
|
||||
target_compile_definitions(test_CDT_3_insert_constrained_edge_from_EDG_file PUBLIC CGAL_TEST_CDT_3_USE_CDT)
|
||||
cgal_add_test(test_CDT_3_insert_constrained_edge_from_EDG_file)
|
||||
|
||||
add_executable(test_CDT_3_insert_constrained_edge_from_OFF_file cdt_test_insert_constrained_edge_from_OFF_file.cpp)
|
||||
target_link_libraries(test_CDT_3_insert_constrained_edge_from_OFF_file PRIVATE CDT_3_dependencies)
|
||||
target_compile_definitions(test_CDT_3_insert_constrained_edge_from_OFF_file PUBLIC CGAL_TEST_CDT_3_USE_CDT)
|
||||
cgal_add_test(test_CDT_3_insert_constrained_edge_from_OFF_file)
|
||||
|
||||
function(CGAL_add_cdt3_from_off_test_aux data_name data_dir)
|
||||
set(options ONLY_MERGE_FACETS)
|
||||
set(oneValueArgs DATA_FILENAME TIMEOUT)
|
||||
set(multiValueArgs LABELS)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 "MY" "${options}" "${oneValueArgs}"
|
||||
"${multiValueArgs}")
|
||||
if(NOT MY_DATA_FILENAME)
|
||||
set(data_filename ${data_name}.off)
|
||||
else()
|
||||
set(data_filename ${MY_DATA_FILENAME})
|
||||
endif()
|
||||
add_test(NAME "execution of cdt_3_from_off ${data_name}"
|
||||
COMMAND cdt_3_from_off
|
||||
--no-merge-facets
|
||||
${data_dir}/${data_filename}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dump_output_${data_name}.off)
|
||||
if(MY_ONLY_MERGE_FACETS)
|
||||
set_property(TEST "execution of cdt_3_from_off ${data_name}" PROPERTY DISABLED TRUE)
|
||||
endif()
|
||||
cgal_setup_test_properties("execution of cdt_3_from_off ${data_name}" cdt_3_from_off)
|
||||
add_test(NAME "execution of cdt_3_from_off --merge-facets ${data_name}"
|
||||
COMMAND cdt_3_from_off
|
||||
--merge-facets --segment-vertex-epsilon 0 --vertex-vertex-epsilon 0
|
||||
${data_dir}/${data_filename}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dump_output_${data_name}--merge-facets.off)
|
||||
cgal_setup_test_properties("execution of cdt_3_from_off --merge-facets ${data_name}" cdt_3_from_off)
|
||||
if(MY_LABELS)
|
||||
set_property(TEST
|
||||
"execution of cdt_3_from_off ${data_name}"
|
||||
"execution of cdt_3_from_off --merge-facets ${data_name}"
|
||||
APPEND PROPERTY LABELS ${MY_LABELS})
|
||||
endif()
|
||||
if(MY_TIMEOUT)
|
||||
set_tests_properties(
|
||||
"execution of cdt_3_from_off ${data_name}"
|
||||
"execution of cdt_3_from_off --merge-facets ${data_name}"
|
||||
PROPERTIES TIMEOUT "${MY_TIMEOUT}")
|
||||
endif()
|
||||
set_property(TEST "execution of cdt_3_from_off ${data_name}" APPEND PROPERTY LABELS CDT_3_WITHOUT_MERGE_FACETS)
|
||||
endfunction()
|
||||
|
||||
function(CGAL_add_cdt3_from_off_test data_name)
|
||||
CGAL_add_cdt3_from_off_test_aux(${data_name} ${CGAL_DATA_DIR}/meshes)
|
||||
endfunction()
|
||||
|
||||
CGAL_add_cdt3_from_off_test("cube")
|
||||
CGAL_add_cdt3_from_off_test("sphere")
|
||||
CGAL_add_cdt3_from_off_test("fandisk")
|
||||
CGAL_add_cdt3_from_off_test("mpi")
|
||||
CGAL_add_cdt3_from_off_test("3torus")
|
||||
CGAL_add_cdt3_from_off_test("cheese-selection")
|
||||
CGAL_add_cdt3_from_off_test("cheese-selection-2")
|
||||
|
||||
function(CGAL_add_cdt3_from_local_off_test data_name)
|
||||
CGAL_add_cdt3_from_off_test_aux(${data_name} ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||
endfunction()
|
||||
|
||||
CGAL_add_cdt3_from_local_off_test(cheese18)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese23)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese28)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese31)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese36-bis)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese36)
|
||||
CGAL_add_cdt3_from_local_off_test(cheese6-PLCerrorWithFace0)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-11)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-1)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-1-min1)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-10a)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-1-reduced)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-1-sv)
|
||||
CGAL_add_cdt3_from_local_off_test(HexiCosPot-1-sv-reduced)
|
||||
CGAL_add_cdt3_from_local_off_test(mpi-part)
|
||||
|
||||
OPTION(CGAL_CDT_TEST_USE_THINGI OFF "Internal switch to test Thingi10k data set")
|
||||
|
||||
if (CGAL_CDT_TEST_USE_THINGI)
|
||||
CGAL_add_cdt3_from_local_off_test(thingi-1036467-selection3)
|
||||
CGAL_add_cdt3_from_local_off_test(243014-min2)
|
||||
CGAL_add_cdt3_from_local_off_test(243014-min3)
|
||||
CGAL_add_cdt3_from_local_off_test(1435440-min1)
|
||||
CGAL_add_cdt3_from_local_off_test(1435440-min2)
|
||||
CGAL_add_cdt3_from_local_off_test(106884-min1)
|
||||
CGAL_add_cdt3_from_local_off_test(113344-min3)
|
||||
CGAL_add_cdt3_from_local_off_test(40985-min3)
|
||||
CGAL_add_cdt3_from_local_off_test(1514904-min8)
|
||||
CGAL_add_cdt3_from_local_off_test(1147177-min1)
|
||||
CGAL_add_cdt3_from_local_off_test(1452672-min1)
|
||||
CGAL_add_cdt3_from_local_off_test(error_mesh-p_not_equal_0-min2)
|
||||
|
||||
include(./Thingi10k-CDT.cmake)
|
||||
endif()
|
||||
|
||||
if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||
add_test(NAME "execution of cdt_3_from_off_CGAL_DEBUG_CDT_3 3torus" COMMAND cdt_3_from_off_CGAL_DEBUG_CDT_3 ${CGAL_DATA_DIR}/meshes/3torus.off)
|
||||
cgal_add_compilation_test(cdt_3_from_off_CGAL_DEBUG_CDT_3)
|
||||
cgal_setup_test_properties("execution of cdt_3_from_off_CGAL_DEBUG_CDT_3 3torus" cdt_3_from_off_CGAL_DEBUG_CDT_3)
|
||||
endif()
|
||||
|
||||
get_directory_property(all_tests TESTS)
|
||||
foreach(test ${all_tests})
|
||||
if(test MATCHES cdt|CDT)
|
||||
get_property(labels TEST ${test} PROPERTY LABELS)
|
||||
if(NOT Thingi10K IN_LIST labels)
|
||||
set_property(TEST ${test} APPEND PROPERTY LABELS CDT_3)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
find_package(ITT QUIET)
|
||||
if(TARGET ITT::ITT)
|
||||
target_link_libraries(cdt_3_from_off PRIVATE ITT::ITT)
|
||||
target_link_libraries(cdt_3_from_off_with_Epeck PRIVATE ITT::ITT)
|
||||
target_compile_definitions(cdt_3_from_off PRIVATE CGAL_USE_ITT)
|
||||
target_compile_definitions(cdt_3_from_off_with_Epeck PRIVATE CGAL_USE_ITT)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
if(CGAL_CDT_3_NO_THINGI10K)
|
||||
return()
|
||||
endif()
|
||||
find_path(THINGI10K_DATA_DIR NAME 132423.stl
|
||||
HINTS ENV HOME
|
||||
PATH_SUFFIXES Downloads/Thingi10K/raw_meshes
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
include(./thingi10k_max_10k_solid.cmake)
|
||||
|
||||
set(thingi10k_BLACKLIST_WITHOUT_MERGE_FACETS
|
||||
#106789.stl
|
||||
# At point 4.0163683382116631 -2.094120689431076 0
|
||||
# There is a edge of the input mesh that is infinitely close to a vertex.
|
||||
)
|
||||
|
||||
set(thingi10k_FAILED_WITH_MERGE_FACETS
|
||||
1053875.stl
|
||||
112926.stl
|
||||
1147177.stl
|
||||
118295.stl
|
||||
123787.stl
|
||||
126284.stl
|
||||
135777.stl
|
||||
1452672.stl
|
||||
1514900.stl
|
||||
1514901.stl
|
||||
1514903.stl
|
||||
1514904.stl
|
||||
162100.stl
|
||||
162336.stl
|
||||
1743322.stl
|
||||
186554.stl
|
||||
186559.stl
|
||||
237737.stl
|
||||
239182.stl
|
||||
255657.stl
|
||||
285604.stl
|
||||
285605.stl
|
||||
288353.stl
|
||||
288354.stl
|
||||
288355.stl
|
||||
383022.stl
|
||||
43663.stl
|
||||
45550.stl
|
||||
464846.stl
|
||||
472002.stl
|
||||
472004.stl
|
||||
472050.stl
|
||||
472190.stl
|
||||
500116.stl
|
||||
520645.stl
|
||||
54467.stl
|
||||
55278.stl
|
||||
57811.stl
|
||||
57812.stl
|
||||
59229.stl
|
||||
67817.stl
|
||||
69260.stl
|
||||
71920.stl
|
||||
74780.stl
|
||||
90224.stl
|
||||
904476.stl
|
||||
904480.stl
|
||||
96046.stl
|
||||
96457.stl
|
||||
96659.stl
|
||||
97503.stl
|
||||
)
|
||||
|
||||
set(thingi10k_FAILED_WITH_MERGE_FACETS_CTest_20240222_2201
|
||||
40119.stl
|
||||
40985.stl
|
||||
41360.stl
|
||||
44903.stl
|
||||
47732.stl
|
||||
55262.stl
|
||||
55278.stl
|
||||
57812.stl
|
||||
58439.stl
|
||||
67817.stl
|
||||
77342.stl
|
||||
80084.stl
|
||||
90224.stl
|
||||
92118.stl
|
||||
97503.stl
|
||||
112926.stl
|
||||
135777.stl
|
||||
162336.stl
|
||||
186544.stl
|
||||
186559.stl
|
||||
225958.stl
|
||||
285604.stl
|
||||
285605.stl
|
||||
288353.stl
|
||||
288354.stl
|
||||
288355.stl
|
||||
375273.stl
|
||||
442387.stl
|
||||
464846.stl
|
||||
904476.stl
|
||||
904480.stl
|
||||
1053875.stl
|
||||
1452672.stl
|
||||
1505023.stl
|
||||
1514904.stl
|
||||
)
|
||||
|
||||
function(CGAL_add_cdt3_test_from_Thingi10k data_name data_filename)
|
||||
set(options "ONLY_MERGE_FACETS")
|
||||
set(oneValueArgs TIMEOUT)
|
||||
set(multiValueArgs LABELS)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 "MY" "${options}" "${oneValueArgs}"
|
||||
"${multiValueArgs}")
|
||||
if(MY_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown arguments specified: ${MY_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(MY_TIMEOUT)
|
||||
set(MY_TIMEOUT_KEYWORD TIMEOUT)
|
||||
endif()
|
||||
if(MY_ONLY_MERGE_FACETS)
|
||||
set(MY_ONLY_MERGE_FACETS ONLY_MERGE_FACETS)
|
||||
endif()
|
||||
CGAL_add_cdt3_from_off_test_aux(${data_name} ${THINGI10K_DATA_DIR} DATA_FILENAME ${data_filename}
|
||||
LABELS ${MY_LABELS}
|
||||
${MY_TIMEOUT_KEYWORD} ${MY_TIMEOUT}
|
||||
${MY_ONLY_MERGE_FACETS}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
foreach(thingi_file_name ${thingi10k_max_10k_solid})
|
||||
|
||||
if(thingi_file_name IN_LIST thingi10k_BLACKLIST_WITHOUT_MERGE_FACETS)
|
||||
set(MY_ONLY_MERGE_FACETS ONLY_MERGE_FACETS)
|
||||
|
||||
unset(MY_ONLY_MERGE_FACETS)
|
||||
endif()
|
||||
set(LABELS Thingi10K Thingi10K_max_10k_solid)
|
||||
if(thingi_file_name IN_LIST thingi10k_FAILED_WITH_MERGE_FACETS)
|
||||
list(APPEND LABELS "Thingi10K_FAIL")
|
||||
endif()
|
||||
if(thingi_file_name IN_LIST thingi10k_FAILED_WITH_MERGE_FACETS_CTest_20240222_2201)
|
||||
list(APPEND LABELS "CTest_20240222_2201_failed_merge_facets")
|
||||
endif()
|
||||
get_filename_component(thingi_ID "${thingi_file_name}" NAME_WE)
|
||||
CGAL_add_cdt3_test_from_Thingi10k(Thingi10K_${thingi_ID} ${thingi_file_name}
|
||||
TIMEOUT 600 LABELS ${LABELS} ${MY_ONLY_MERGE_FACETS})
|
||||
endforeach()
|
||||
|
|
@ -0,0 +1,959 @@
|
|||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4455)
|
||||
#endif
|
||||
|
||||
#if defined(CGAL_DEBUG_CDT_3) && !__has_include(<format>)
|
||||
#undef CGAL_DEBUG_CDT_3
|
||||
#endif
|
||||
|
||||
// #define CGAL_CDT_2_DEBUG_INTERSECTIONS 1
|
||||
#define NO_TRY_CATCH 1
|
||||
// #define CGAL_DEBUG_CDT_3 1
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Constrained_triangulation_3/internal/read_polygon_mesh_for_cdt_3.h>
|
||||
#include <CGAL/IO/File_binary_mesh_3.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Polygon_mesh_processing/region_growing.h>
|
||||
#include <CGAL/Polygon_mesh_processing/remesh_planar_patches.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#if CGAL_CXX20 && __cpp_lib_concepts >= 201806L && __cpp_lib_ranges >= 201911L
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
#include <optional>
|
||||
#include <chrono>
|
||||
|
||||
#if CGAL_CDT_3_USE_EPECK
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
#else // use Epick
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
#endif // use Epick
|
||||
|
||||
struct Vb : public CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<K> {};
|
||||
struct Cb : public CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<K> {};
|
||||
struct Tds: public CGAL::Triangulation_data_structure_3<Vb, Cb> {};
|
||||
using Base_triantulation = CGAL::Delaunay_triangulation_3<K, Tds>;
|
||||
using CDT = CGAL::Conforming_constrained_Delaunay_triangulation_3_impl<Base_triantulation>;
|
||||
using Point = Base_triantulation::Point;
|
||||
using Point_3 = K::Point_3;
|
||||
|
||||
using Mesh = CGAL::Surface_mesh<Point>;
|
||||
using vertex_descriptor = boost::graph_traits<Mesh>::vertex_descriptor;
|
||||
using edge_descriptor = boost::graph_traits<Mesh>::edge_descriptor;
|
||||
using face_descriptor = boost::graph_traits<Mesh>::face_descriptor;
|
||||
|
||||
void help(std::ostream& out) {
|
||||
out << R"!!!!!(
|
||||
Usage: cdt_3_from_off [options] input.off output.off
|
||||
|
||||
input.off: input mesh
|
||||
output.off: output mesh
|
||||
|
||||
--merge-facets/--no-merge-facets: merge facets into patches (set by default)
|
||||
--merge-facets-old: merge facets using the old method
|
||||
--use-new-cavity-algorithm/--use-old-cavity-algorithm: use new or old cavity algorithm (default: new)
|
||||
--failure-expression <expression>: expression to detect bad meshratio)
|
||||
--ratio <double>: ratio of faces to remove (default: 0.1), if --failure-expression is used
|
||||
--vertex-vertex-epsilon <double>: epsilon for vertex-vertex min distance (default: 1e-6)
|
||||
--segment-vertex-epsilon <double>: epsilon for segment-vertex min distance (default: 0)
|
||||
--coplanar-polygon-max-angle <double>: max angle for coplanar polygons (default: 1)
|
||||
--coplanar-polygon-max-distance <double>: max distance for coplanar polygons (default: 1e-6)
|
||||
|
||||
--dump-patches-after-merge <filename.ply>: dump patches after merging facets in PLY
|
||||
--dump-surface-mesh-after-merge <filename.off>: dump surface mesh after merging facets in OFF
|
||||
--dump-patches-borders-prefix <filenames_prefix>: dump patches borders
|
||||
--dump-after-conforming <filename.off>: dump mesh after conforming in OFF
|
||||
|
||||
--no-repair: do not repair the mesh
|
||||
--reject-self-intersections: reject self-intersecting polygon soups
|
||||
--no-is-valid: do not call is_valid checks
|
||||
--debug-input-faces: debug input faces
|
||||
--debug-missing-regions: debug missing regions
|
||||
--debug-regions: debug regions
|
||||
--debug_copy_triangulation_into_hole: debug copy_triangulation_into_hole
|
||||
--debug-validity: add is_valid checks after modifications to the TDS
|
||||
--debug-finite-edges-map: debug the use of a hash map for finite edges
|
||||
--use-finite-edges-map: use a hash map for finite edges (default: false)
|
||||
|
||||
--verbose/-V: verbose (can be used several times)
|
||||
--quiet: do not print anything
|
||||
--help/-h: print this help
|
||||
)!!!!!";
|
||||
}
|
||||
|
||||
[[noreturn]] void error(std::string_view message, std::string_view extra = "") {
|
||||
std::cerr << "Error: " << message << extra << '\n';
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct CDT_options
|
||||
{
|
||||
int verbose_level = 0;
|
||||
bool need_help = false;
|
||||
bool quiet = false;
|
||||
bool merge_facets = true;
|
||||
bool merge_facets_old_method = false;
|
||||
bool reject_self_intersections = false;
|
||||
bool repair_mesh = true;
|
||||
bool debug_input_faces = false;
|
||||
bool debug_missing_regions = false;
|
||||
bool debug_regions = false;
|
||||
bool debug_copy_triangulation_into_hole = false;
|
||||
bool use_new_cavity_algorithm = true;
|
||||
bool debug_validity = false;
|
||||
bool debug_finite_edges_map = false;
|
||||
bool use_finite_edges_map = false;
|
||||
bool call_is_valid = true;
|
||||
double ratio = 0.1;
|
||||
double vertex_vertex_epsilon = 1e-14;
|
||||
double segment_vertex_epsilon = 1e-14;
|
||||
double coplanar_polygon_max_angle = 5.1;
|
||||
double coplanar_polygon_max_distance = 1e-6;
|
||||
std::string failure_assertion_expression {};
|
||||
std::string input_filename = CGAL::data_file_path("meshes/mpi.off");
|
||||
std::string output_filename {"dump.off"};
|
||||
std::string dump_patches_after_merge_filename {};
|
||||
std::string dump_surface_mesh_after_merge_filename{};
|
||||
std::string dump_patches_borders_prefix {};
|
||||
std::string dump_after_conforming_filename {};
|
||||
|
||||
CDT_options(int argc, char* argv[]);
|
||||
};
|
||||
|
||||
CDT_options::CDT_options(int argc, char* argv[]) {
|
||||
const std::vector<std::string_view> args(argv + 1, argv + argc);
|
||||
int positional = 0;
|
||||
|
||||
using std::literals::string_view_literals::operator""sv;
|
||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||
auto get_next_arg_or_error_out = [&it, &args]() -> std::string {
|
||||
if(it + 1 == args.end()) {
|
||||
error("extra argument required after "sv, *it);
|
||||
}
|
||||
return std::string(*++it);
|
||||
};
|
||||
std::string_view arg = *it;
|
||||
if(arg == "--merge-facets"sv) {
|
||||
merge_facets = true;
|
||||
} else if(arg == "--no-merge-facets"sv) {
|
||||
merge_facets = false;
|
||||
} else if(arg == "--use-new-cavity-algorithm"sv) {
|
||||
use_new_cavity_algorithm = true;
|
||||
} else if(arg == "--use-old-cavity-algorithm"sv) {
|
||||
use_new_cavity_algorithm = false;
|
||||
} else if(arg == "--reject-self-intersections"sv) {
|
||||
reject_self_intersections = true;
|
||||
} else if(arg == "--no-repair"sv) {
|
||||
repair_mesh = false;
|
||||
} else if(arg == "--merge-facets-old"sv) {
|
||||
merge_facets = true;
|
||||
merge_facets_old_method = true;
|
||||
} else if(arg == "--failure-expression"sv) {
|
||||
failure_assertion_expression = get_next_arg_or_error_out();
|
||||
} else if(arg == "--ratio"sv) {
|
||||
ratio = std::stod(get_next_arg_or_error_out());
|
||||
} else if(arg == "--dump-patches-after-merge"sv) {
|
||||
dump_patches_after_merge_filename = get_next_arg_or_error_out();
|
||||
} else if(arg == "--dump-patches-borders-prefix"sv) {
|
||||
dump_patches_borders_prefix = get_next_arg_or_error_out();
|
||||
} else if(arg == "--dump-surface-mesh-after-merge"sv) {
|
||||
dump_surface_mesh_after_merge_filename = get_next_arg_or_error_out();
|
||||
} else if(arg == "--dump-after-conforming"sv) {
|
||||
dump_after_conforming_filename = get_next_arg_or_error_out();
|
||||
} else if(arg == "--vertex-vertex-epsilon"sv) {
|
||||
vertex_vertex_epsilon = std::stod(get_next_arg_or_error_out());
|
||||
} else if(arg == "--segment-vertex-epsilon"sv) {
|
||||
segment_vertex_epsilon = std::stod(get_next_arg_or_error_out());
|
||||
} else if(arg == "--coplanar-polygon-max-angle"sv) {
|
||||
coplanar_polygon_max_angle = std::stod(get_next_arg_or_error_out());
|
||||
} else if(arg == "--coplanar-polygon-max-distance"sv) {
|
||||
coplanar_polygon_max_distance = std::stod(get_next_arg_or_error_out());
|
||||
} else if(arg == "--quiet"sv) {
|
||||
quiet = true;
|
||||
} else if(arg == "--no-is-valid"sv) {
|
||||
call_is_valid = false;
|
||||
} else if(arg == "--debug-input-faces"sv) {
|
||||
debug_input_faces = true;
|
||||
} else if(arg == "--debug-missing-regions"sv) {
|
||||
debug_missing_regions = true;
|
||||
} else if(arg == "--debug-regions"sv) {
|
||||
debug_regions = true;
|
||||
} else if(arg == "--debug_copy_triangulation_into_hole"sv) {
|
||||
debug_copy_triangulation_into_hole = true;
|
||||
} else if(arg == "--debug-validity"sv) {
|
||||
debug_validity = true;
|
||||
} else if(arg == "--debug-finite-edges-map"sv) {
|
||||
debug_finite_edges_map = true;
|
||||
} else if(arg == "--use-finite-edges-map"sv) {
|
||||
use_finite_edges_map = true;
|
||||
} else if(arg == "--verbose"sv || arg == "-V"sv) {
|
||||
++verbose_level;
|
||||
} else if(arg == "--help"sv || arg == "-h"sv) {
|
||||
need_help = true;
|
||||
} else if(arg[0] == '-') {
|
||||
error("unknown option "sv, arg);
|
||||
} else {
|
||||
switch(positional) {
|
||||
case 0:
|
||||
input_filename = arg;
|
||||
++positional;
|
||||
break;
|
||||
case 1:
|
||||
output_filename = arg;
|
||||
++positional;
|
||||
break;
|
||||
default:
|
||||
error("too many arguments"sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NO_TRY_CATCH
|
||||
# define CDT_3_try if (true)
|
||||
# define CDT_3_catch(X) if (false)
|
||||
# define CDT_3_throw_exception_again
|
||||
#else
|
||||
// Else proceed normally.
|
||||
# define CDT_3_try try
|
||||
# define CDT_3_catch(X) catch(X)
|
||||
# define CDT_3_throw_exception_again throw
|
||||
#endif
|
||||
|
||||
#if CGAL_USE_ITT
|
||||
# include <ittnotify.h>
|
||||
# define CGAL_CDT_3_TASK_BEGIN(task_handle) \
|
||||
std::cerr << "START " << #task_handle << '\n'; \
|
||||
__itt_task_begin(cdt_3_domain, __itt_null, __itt_null, task_handle);
|
||||
# define CGAL_CDT_3_TASK_END(task_handle) \
|
||||
std::cerr << "-STOP " << #task_handle << '\n'; \
|
||||
__itt_task_end(cdt_3_domain);
|
||||
|
||||
auto cdt_3_domain = __itt_domain_create("org.cgal.CDT_3");
|
||||
auto read_input_task_handle = __itt_string_handle_create("CDT_3: read input file");
|
||||
auto merge_facets_task_handle = __itt_string_handle_create("CDT_3: merge facets");
|
||||
auto insert_vertices_task_handle = __itt_string_handle_create("CDT_3: insert vertices");
|
||||
auto compute_distances_task_handle = __itt_string_handle_create("CDT_3: compute distances");
|
||||
auto conforming_task_handle = __itt_string_handle_create("CDT_3: conforming");
|
||||
auto cdt_task_handle = __itt_string_handle_create("CDT_3: cdt");
|
||||
auto output_task_handle = __itt_string_handle_create("CDT_3: outputs");
|
||||
auto validation_task_handle = __itt_string_handle_create("CDT_3: validation");
|
||||
|
||||
#else // no ITT
|
||||
# define CGAL_CDT_3_TASK_BEGIN(task_handle)
|
||||
# define CGAL_CDT_3_TASK_END(task_handle)
|
||||
#endif // no ITT
|
||||
|
||||
int go(Mesh mesh, CDT_options options) {
|
||||
CDT cdt;
|
||||
cdt.debug_Steiner_points(options.verbose_level > 0);
|
||||
cdt.debug_input_faces(options.debug_input_faces);
|
||||
cdt.debug_missing_region(options.verbose_level > 1 || options.debug_missing_regions);
|
||||
cdt.debug_regions(options.debug_regions);
|
||||
cdt.debug_validity(options.debug_validity);
|
||||
cdt.debug_finite_edges_map(options.debug_finite_edges_map);
|
||||
cdt.debug_copy_triangulation_into_hole(options.debug_copy_triangulation_into_hole);
|
||||
cdt.use_older_cavity_algorithm(!options.use_new_cavity_algorithm);
|
||||
cdt.use_finite_edges_map(options.use_finite_edges_map);
|
||||
cdt.set_segment_vertex_epsilon(options.segment_vertex_epsilon);
|
||||
|
||||
const auto bbox = CGAL::Polygon_mesh_processing::bbox(mesh);
|
||||
double d_x = bbox.xmax() - bbox.xmin();
|
||||
double d_y = bbox.ymax() - bbox.ymin();
|
||||
double d_z = bbox.zmax() - bbox.zmin();
|
||||
|
||||
const double bbox_max_width = (std::max)(d_x, (std::max)(d_y, d_z));
|
||||
|
||||
double epsilon = options.vertex_vertex_epsilon;
|
||||
|
||||
if(!options.quiet) {
|
||||
std::cout << "Bbox width : " << bbox_max_width << '\n'
|
||||
<< "Epsilon : " << epsilon << '\n'
|
||||
<< "Epsilon * Bbox width : " << epsilon * bbox_max_width << "\n\n";
|
||||
}
|
||||
|
||||
auto pmap = get(CGAL::vertex_point, mesh);
|
||||
|
||||
auto [patch_id_map, patch_id_map_ok] = mesh.add_property_map<face_descriptor, int>("f:patch_id", -2);
|
||||
assert(patch_id_map_ok); CGAL_USE(patch_id_map_ok);
|
||||
auto [v_selected_map, v_selected_map_ok] = mesh.add_property_map<vertex_descriptor, bool>("v:selected", false);
|
||||
assert(v_selected_map_ok); CGAL_USE(v_selected_map_ok);
|
||||
auto [edge_is_border_of_patch_map, edge_is_border_of_patch_map_ok] =
|
||||
mesh.add_property_map<edge_descriptor, bool>("e:is_border_of_patch", false);
|
||||
assert(edge_is_border_of_patch_map_ok);
|
||||
CGAL_USE(edge_is_border_of_patch_map_ok);
|
||||
int nb_patches = 0;
|
||||
std::vector<std::vector<std::pair<vertex_descriptor, vertex_descriptor>>> patch_edges;
|
||||
if(options.merge_facets) {
|
||||
CGAL_CDT_3_TASK_BEGIN(merge_facets_task_handle);
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if(options.merge_facets_old_method) {
|
||||
for(auto f: faces(mesh))
|
||||
{
|
||||
if(get(patch_id_map, f) >= 0) continue;
|
||||
std::stack<face_descriptor> f_stack;
|
||||
f_stack.push(f);
|
||||
while(!f_stack.empty()) {
|
||||
auto f = f_stack.top();
|
||||
f_stack.pop();
|
||||
if(get(patch_id_map, f) >= 0) continue;
|
||||
put(patch_id_map, f, nb_patches);
|
||||
for(auto h: CGAL::halfedges_around_face(halfedge(f, mesh), mesh)) {
|
||||
auto opp = opposite(h, mesh);
|
||||
if(is_border_edge(opp, mesh)) {
|
||||
continue;
|
||||
}
|
||||
auto n = face(opp, mesh);
|
||||
auto a = get(pmap, source(h, mesh));
|
||||
auto b = get(pmap, target(h, mesh));
|
||||
auto c = get(pmap, target(next(h, mesh), mesh));
|
||||
auto d = get(pmap, target(next(opp, mesh), mesh));
|
||||
if(CGAL::orientation(a, b, c, d) != CGAL::COPLANAR) {
|
||||
continue;
|
||||
}
|
||||
if(get(patch_id_map, n) >= 0) continue;
|
||||
f_stack.push(n);
|
||||
}
|
||||
}
|
||||
++nb_patches;
|
||||
}
|
||||
} else {
|
||||
namespace np = CGAL::parameters;
|
||||
nb_patches = CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces(
|
||||
mesh, patch_id_map,
|
||||
np::maximum_distance(options.coplanar_polygon_max_distance * bbox_max_width)
|
||||
.maximum_angle(options.coplanar_polygon_max_angle));
|
||||
for(auto f: faces(mesh)) {
|
||||
if(get(patch_id_map, f) < 0) {
|
||||
std::cerr << "warning: face " << f << " has no patch id! Reassign it to " << nb_patches << '\n';
|
||||
for(auto h: CGAL::halfedges_around_face(halfedge(f, mesh), mesh)) {
|
||||
std::cerr << " " << target(h, mesh) << ", point " << mesh.point(target(h, mesh)) << '\n';
|
||||
}
|
||||
put(patch_id_map, f, nb_patches++);
|
||||
}
|
||||
}
|
||||
if(!options.dump_surface_mesh_after_merge_filename.empty()) {
|
||||
auto [corner_id_map, corner_id_map_ok] = mesh.add_property_map<vertex_descriptor, std::size_t>("v:corner_id", -1);
|
||||
assert(corner_id_map_ok);
|
||||
CGAL_USE(corner_id_map_ok);
|
||||
const auto nb_corners = CGAL::Polygon_mesh_processing::detect_corners_of_regions(
|
||||
mesh, patch_id_map, nb_patches, corner_id_map,
|
||||
np::maximum_distance(options.coplanar_polygon_max_distance * bbox_max_width)
|
||||
.maximum_angle(options.coplanar_polygon_max_angle)
|
||||
.edge_is_constrained_map(edge_is_border_of_patch_map));
|
||||
Mesh merged_mesh;
|
||||
CGAL::Polygon_mesh_processing::remesh_almost_planar_patches(
|
||||
mesh, merged_mesh, nb_patches, nb_corners, patch_id_map, corner_id_map, edge_is_border_of_patch_map,
|
||||
CGAL::parameters::default_values(),
|
||||
CGAL::parameters::do_not_triangulate_faces(true));
|
||||
mesh.remove_property_map(corner_id_map);
|
||||
std::ofstream out(options.dump_surface_mesh_after_merge_filename);
|
||||
out.precision(17);
|
||||
out << merged_mesh;
|
||||
}
|
||||
}
|
||||
if (!options.quiet) {
|
||||
std::cout << "[timings] detected " << nb_patches << " patches in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
}
|
||||
patch_edges.resize(nb_patches);
|
||||
for(auto h: halfedges(mesh))
|
||||
{
|
||||
if(is_border(h, mesh)) continue;
|
||||
auto f = face(h, mesh);
|
||||
auto patch_id = get(patch_id_map, f);
|
||||
auto opp = opposite(h, mesh);
|
||||
if(is_border(opp, mesh) || patch_id != get(patch_id_map, face(opp, mesh))) {
|
||||
auto va = source(h, mesh);
|
||||
auto vb = target(h, mesh);
|
||||
patch_edges[patch_id].emplace_back(va, vb);
|
||||
put(v_selected_map, va, true);
|
||||
put(v_selected_map, vb, true);
|
||||
}
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(merge_facets_task_handle);
|
||||
if(!options.dump_patches_after_merge_filename.empty()) {
|
||||
CGAL_CDT_3_TASK_BEGIN(output_task_handle);
|
||||
std::ofstream out(options.dump_patches_after_merge_filename);
|
||||
CGAL::IO::write_PLY(out, mesh, CGAL::parameters::stream_precision(17));
|
||||
CGAL_CDT_3_TASK_END(output_task_handle);
|
||||
}
|
||||
}
|
||||
if(!options.dump_patches_borders_prefix.empty()) {
|
||||
CGAL_CDT_3_TASK_BEGIN(output_task_handle);
|
||||
std::set<std::pair<vertex_descriptor, vertex_descriptor>> all_edges;
|
||||
for(int i = 0; i < nb_patches; ++i) {
|
||||
std::stringstream ss;
|
||||
ss << options.dump_patches_borders_prefix << i << ".polylines.txt";
|
||||
std::ofstream out(ss.str());
|
||||
out.precision(17);
|
||||
const auto& edges = patch_edges[i];
|
||||
for(auto [va, vb]: edges) {
|
||||
all_edges.insert(CGAL::make_sorted_pair(va, vb));
|
||||
}
|
||||
std::cerr << "Patch p#" << i << " has " << edges.size() << " edges\n";
|
||||
const auto polylines = segment_soup_to_polylines(edges);
|
||||
for(const auto& polyline: polylines) {
|
||||
out << polyline.size() << " ";
|
||||
for(auto v: polyline) {
|
||||
out << get(pmap, v) << " ";
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
out.close();
|
||||
std::cerr << " " << polylines.size() << " polylines\n";
|
||||
for(const auto& polyline: polylines) {
|
||||
std::cerr << " - " << polyline.size() << " vertices\n";
|
||||
assert(polyline.front() == polyline.back());
|
||||
}
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << options.dump_patches_borders_prefix << "all_edges.polylines.txt";
|
||||
std::ofstream out(ss.str());
|
||||
out.precision(17);
|
||||
const auto polylines = segment_soup_to_polylines(all_edges);
|
||||
for(const auto& polyline: polylines) {
|
||||
out << polyline.size() << " ";
|
||||
for(auto v: polyline) {
|
||||
out << get(pmap, v) << " ";
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(output_task_handle);
|
||||
}
|
||||
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
|
||||
auto finally = [&cdt, &options]() {
|
||||
CGAL_CDT_3_TASK_BEGIN(output_task_handle);
|
||||
{
|
||||
auto dump_tets_to_medit = [](std::string fname,
|
||||
const std::vector<K::Point_3> &points,
|
||||
const std::vector<std::array<std::size_t, 4>> &indexed_tetra,
|
||||
const std::vector<std::size_t> &cell_ids)
|
||||
{
|
||||
std::ofstream out(fname);
|
||||
out.precision(17);
|
||||
out << "MeshVersionFormatted 1\nDimension 3\nVertices\n";
|
||||
out << points.size() << "\n";
|
||||
for (const K::Point_3& p : points)
|
||||
out << p << " 0\n";
|
||||
out << "Triangles\n0\nTetrahedra\n";
|
||||
out << indexed_tetra.size() << "\n";
|
||||
for (std::size_t k=0;k<indexed_tetra.size(); ++k)
|
||||
out << indexed_tetra[k][0]+1 << " "
|
||||
<< indexed_tetra[k][1]+1 << " "
|
||||
<< indexed_tetra[k][2]+1 << " "
|
||||
<< indexed_tetra[k][3]+1 << " " << cell_ids[k] << "\n";
|
||||
out <<"End\n";
|
||||
};
|
||||
|
||||
auto& tr = cdt;
|
||||
|
||||
std::unordered_map<CDT::Cell_handle, int /*Subdomain_index*/> cells_map;
|
||||
for(auto ch : tr.all_cell_handles())
|
||||
{
|
||||
cells_map[ch] = 1;
|
||||
}
|
||||
|
||||
std::stack<decltype(tr.infinite_cell())> stack;
|
||||
stack.push(tr.infinite_cell());
|
||||
while (!stack.empty())
|
||||
{
|
||||
auto ch = stack.top();
|
||||
stack.pop();
|
||||
cells_map[ch] = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if(ch->ccdt_3_data().is_facet_constrained(i))
|
||||
continue;
|
||||
auto n = ch->neighbor(i);
|
||||
if (cells_map[n] == 1)
|
||||
{
|
||||
stack.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<K::Point_3> points(cdt.number_of_vertices());
|
||||
for(auto v: cdt.finite_vertex_handles()) {
|
||||
points.at(v->time_stamp() -1) = v->point();
|
||||
}
|
||||
std::vector<std::array<std::size_t, 4>> indexed_tetra;
|
||||
indexed_tetra.reserve(cdt.number_of_cells());
|
||||
for(auto ch: cdt.finite_cell_handles()) {
|
||||
if(cells_map[ch] > 0) {
|
||||
indexed_tetra.push_back({ch->vertex(0)->time_stamp() -1,
|
||||
ch->vertex(1)->time_stamp() -1,
|
||||
ch->vertex(2)->time_stamp() -1,
|
||||
ch->vertex(3)->time_stamp() -1});
|
||||
}
|
||||
}
|
||||
std::vector<std::size_t> cell_idsl(indexed_tetra.size(), 1);
|
||||
dump_tets_to_medit(options.output_filename + ".mesh", points, indexed_tetra, cell_idsl);
|
||||
}
|
||||
{
|
||||
std::ofstream dump(options.output_filename);
|
||||
dump.precision(17);
|
||||
#if CGAL_CXX20 && __cpp_lib_concepts >= 201806L && __cpp_lib_ranges >= 201911L
|
||||
cdt.write_facets(dump, cdt, std::views::filter(cdt.finite_facets(), [&](auto f) {
|
||||
return cdt.is_facet_constrained(f);
|
||||
}));
|
||||
#else
|
||||
auto is_facet_constrained = [&](auto f) { return cdt.is_facet_constrained(f); };
|
||||
auto it_end = cdt.finite_facets_end();
|
||||
cdt.write_facets(dump, cdt,
|
||||
CGAL::make_range(
|
||||
boost::make_filter_iterator(is_facet_constrained,cdt.finite_facets_begin(), it_end),
|
||||
boost::make_filter_iterator(is_facet_constrained,it_end, it_end)));
|
||||
|
||||
#endif
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(output_task_handle);
|
||||
};
|
||||
|
||||
auto [tr_vertex_pmap, tr_vertex_pmap_ok] = mesh.add_property_map<vertex_descriptor, CDT::Vertex_handle>("tr_vertex");
|
||||
assert(tr_vertex_pmap_ok); CGAL_USE(tr_vertex_pmap_ok);
|
||||
|
||||
CGAL_CDT_3_TASK_BEGIN(insert_vertices_task_handle);
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
CDT::Cell_handle hint{};
|
||||
for(auto v: vertices(mesh)) {
|
||||
if(options.merge_facets && false == get(v_selected_map, v)) continue;
|
||||
auto vh = cdt.insert(get(pmap, v), hint, false);
|
||||
hint = vh->cell();
|
||||
put(tr_vertex_pmap, v, vh);
|
||||
}
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] inserted vertices in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
std::cout << "Number of vertices: " << cdt.number_of_vertices() << "\n\n";
|
||||
}
|
||||
if(cdt.dimension() < 3) {
|
||||
if(!options.quiet) {
|
||||
std::cout << "current is 2D... inserting the 8 vertices of an extended bounding box\n";
|
||||
}
|
||||
if(d_x == 0) d_x = bbox_max_width;
|
||||
if(d_y == 0) d_y = bbox_max_width;
|
||||
if(d_z == 0) d_z = bbox_max_width;
|
||||
|
||||
cdt.insert(Point(bbox.xmin() - d_x, bbox.ymin() - d_y, bbox.zmin() - d_z));
|
||||
cdt.insert(Point(bbox.xmin() - d_x, bbox.ymax() + d_y, bbox.zmin() - d_z));
|
||||
cdt.insert(Point(bbox.xmin() - d_x, bbox.ymin() - d_y, bbox.zmax() + d_z));
|
||||
cdt.insert(Point(bbox.xmin() - d_x, bbox.ymax() + d_y, bbox.zmax() + d_z));
|
||||
cdt.insert(Point(bbox.xmax() + d_x, bbox.ymin() - d_y, bbox.zmin() - d_z));
|
||||
cdt.insert(Point(bbox.xmax() + d_x, bbox.ymax() + d_y, bbox.zmin() - d_z));
|
||||
cdt.insert(Point(bbox.xmax() + d_x, bbox.ymin() - d_y, bbox.zmax() + d_z));
|
||||
cdt.insert(Point(bbox.xmax() + d_x, bbox.ymax() + d_y, bbox.zmax() + d_z));
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(insert_vertices_task_handle);
|
||||
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
CGAL_CDT_3_TASK_BEGIN(compute_distances_task_handle);
|
||||
{
|
||||
#if CGAL_CXX20 && __cpp_lib_concepts >= 201806L && __cpp_lib_ranges >= 201911L
|
||||
auto [min_sq_distance, min_edge] = (std::ranges::min)(
|
||||
cdt.finite_edges() | std::views::transform([&](auto edge) { return std::make_pair(cdt.segment(edge).squared_length(), edge); }));
|
||||
#else
|
||||
auto trsf = [&](auto edge) { return std::make_pair(cdt.segment(edge).squared_length(), edge); };
|
||||
auto min_p = trsf(*cdt.finite_edges_begin());
|
||||
for (auto ite=cdt.finite_edges_begin(); ite!=cdt.finite_edges_end(); ++ite)
|
||||
{
|
||||
auto p = trsf(*ite);
|
||||
if (p < min_p)
|
||||
p = min_p;
|
||||
}
|
||||
auto [min_sq_distance, min_edge] = min_p;
|
||||
#endif
|
||||
auto min_distance = CGAL::approximate_sqrt(min_sq_distance);
|
||||
auto vertices_of_min_edge = cdt.vertices(min_edge);
|
||||
if(!options.quiet) {
|
||||
std::cout << "Min distance between vertices: " << min_distance << '\n'
|
||||
<< " between vertices: : " << CGAL::IO::oformat(vertices_of_min_edge[0], CGAL::With_point_tag{})
|
||||
<< " " << CGAL::IO::oformat(vertices_of_min_edge[1], CGAL::With_point_tag{}) << "\n\n";
|
||||
}
|
||||
if(min_distance < epsilon * bbox_max_width) {
|
||||
std::cerr << "ERROR: min distance between vertices is too small\n";
|
||||
exit_code = EXIT_FAILURE;
|
||||
return exit_code;
|
||||
}
|
||||
}
|
||||
{
|
||||
double min_distance = (std::numeric_limits<double>::max)();
|
||||
CDT::Vertex_handle min_va, min_vb, min_vertex;
|
||||
if(options.merge_facets) {
|
||||
for(int i = 0; i < nb_patches; ++i) {
|
||||
const auto& edges = patch_edges[i];
|
||||
for(auto [vda, vdb]: edges) {
|
||||
auto va = get(tr_vertex_pmap, vda);
|
||||
auto vb = get(tr_vertex_pmap, vdb);
|
||||
auto [min_dist, min_v] = cdt.min_distance_and_vertex_between_constraint_and_encroaching_vertex(va, vb);
|
||||
if(min_dist < min_distance) {
|
||||
min_distance = CGAL::to_double(min_dist);
|
||||
min_va = va;
|
||||
min_vb = vb;
|
||||
min_vertex = min_v;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto face_descriptor : faces(mesh)) {
|
||||
auto he = halfedge(face_descriptor, mesh);
|
||||
const auto end = he;
|
||||
do {
|
||||
auto va = get(tr_vertex_pmap, source(he, mesh));
|
||||
auto vb = get(tr_vertex_pmap, target(he, mesh));
|
||||
auto [min_dist, min_v] = cdt.min_distance_and_vertex_between_constraint_and_encroaching_vertex(va, vb);
|
||||
if(min_dist < min_distance) {
|
||||
min_distance = CGAL::to_double(min_dist);
|
||||
min_va = va;
|
||||
min_vb = vb;
|
||||
min_vertex = min_v;
|
||||
}
|
||||
he = next(he, mesh);
|
||||
} while((he = next(he, mesh)) != end);
|
||||
}
|
||||
}
|
||||
if(!options.quiet) {
|
||||
std::cout << "Min distance between constraint segment and vertex: " << min_distance << '\n'
|
||||
<< " between segment : "
|
||||
<< CGAL::IO::oformat(min_va, CDT::Conforming_Dt::with_point) << " "
|
||||
<< CGAL::IO::oformat(min_vb, CDT::Conforming_Dt::with_point) << '\n'
|
||||
<< " and vertex : "
|
||||
<< CGAL::IO::oformat(min_vertex, CDT::Conforming_Dt::with_point) << "\n\n";
|
||||
}
|
||||
cdt.check_segment_vertex_distance_or_throw(min_va, min_vb, min_vertex, min_distance,
|
||||
CDT::Check_distance::NON_SQUARED_DISTANCE);
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(compute_distances_task_handle);
|
||||
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] compute distances on " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
}
|
||||
int poly_id = 0;
|
||||
CGAL_CDT_3_TASK_BEGIN(conforming_task_handle);
|
||||
CDT_3_try {
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
if(options.merge_facets) {
|
||||
for(int i = 0; i < nb_patches; ++i) {
|
||||
auto& edges = patch_edges[i];
|
||||
auto polylines = segment_soup_to_polylines(edges);
|
||||
while(true) {
|
||||
const auto non_closed_polylines_begin =
|
||||
std::partition(polylines.begin(), polylines.end(),
|
||||
[](const auto& polyline) { return polyline.front() == polyline.back(); });
|
||||
if(non_closed_polylines_begin == polylines.end())
|
||||
break;
|
||||
edges.clear();
|
||||
for(auto it = non_closed_polylines_begin; it != polylines.end(); ++it) {
|
||||
auto& polyline = *it;
|
||||
for(auto it = polyline.begin(), end = polyline.end() - 1; it != end; ++it) {
|
||||
edges.emplace_back(*it, *(it + 1));
|
||||
}
|
||||
}
|
||||
polylines.erase(non_closed_polylines_begin, polylines.end());
|
||||
auto other_polylines = segment_soup_to_polylines(edges);
|
||||
polylines.insert(polylines.end(),
|
||||
std::make_move_iterator(other_polylines.begin()),
|
||||
std::make_move_iterator(other_polylines.end()));
|
||||
}
|
||||
|
||||
std::optional<int> face_index;
|
||||
for(auto& polyline: polylines) {
|
||||
assert(polyline.front() == polyline.back());
|
||||
polyline.pop_back();
|
||||
#if CGAL_CXX20 && __cpp_lib_concepts >= 201806L && __cpp_lib_ranges >= 201911L
|
||||
face_index = cdt.insert_constrained_face(
|
||||
polyline | std::views::transform([&](vertex_descriptor v) { return get(tr_vertex_pmap, v); }),
|
||||
false,
|
||||
face_index ? *face_index : -1);
|
||||
#else
|
||||
face_index = cdt.insert_constrained_face( CGAL::Iterator_range(CGAL::make_transform_iterator_from_property_map(polyline.begin(), tr_vertex_pmap),
|
||||
CGAL::make_transform_iterator_from_property_map(polyline.end(), tr_vertex_pmap)),
|
||||
false,
|
||||
face_index ? *face_index : -1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto face_descriptor : faces(mesh)) {
|
||||
std::vector<Point_3> polygon;
|
||||
const auto he = halfedge(face_descriptor, mesh);
|
||||
for(auto vertex_it : CGAL::vertices_around_face(he, mesh)) {
|
||||
polygon.push_back(get(pmap, vertex_it));
|
||||
}
|
||||
#if CGAL_DEBUG_CDT_3
|
||||
std::cerr << "NEW POLYGON #" << poly_id << '\n';
|
||||
#endif // CGAL_DEBUG_CDT_3
|
||||
try {
|
||||
[[maybe_unused]] auto id = cdt.insert_constrained_polygon(polygon, false);
|
||||
assert(id == poly_id);
|
||||
++poly_id;
|
||||
} catch(int error) {
|
||||
exit_code = error;
|
||||
}
|
||||
// std::ofstream dump("dump.binary.cgal");
|
||||
// CGAL::Mesh_3::save_binary_file(dump, cdt);
|
||||
}
|
||||
} // not merge_facets
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] registered facets in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
}
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
cdt.restore_Delaunay();
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] restored Delaunay (conforming of facets borders) in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(conforming_task_handle);
|
||||
|
||||
if(!options.dump_after_conforming_filename.empty()) {
|
||||
CGAL_CDT_3_TASK_BEGIN(output_task_handle);
|
||||
using Vertex_index = Mesh::Vertex_index;
|
||||
[[maybe_unused]] std::size_t time_stamp_counter = 0u;
|
||||
for(auto v: cdt.finite_vertex_handles()) {
|
||||
[[maybe_unused]] const auto time_stamp = v->time_stamp();
|
||||
assert(++time_stamp_counter == time_stamp);
|
||||
if(!v->ccdt_3_data().is_Steiner_vertex_on_edge()) continue;
|
||||
const auto [va, vb] = cdt.ancestors_of_Steiner_vertex_on_edge(v);
|
||||
const auto index_va = Vertex_index{static_cast<unsigned>(va->time_stamp() - 1)};
|
||||
const auto index_vb = Vertex_index{static_cast<unsigned>(vb->time_stamp() - 1)};
|
||||
auto [it, end] = CGAL::halfedges_around_source(index_va, mesh);
|
||||
// std::cerr << " around mesh vertex " << index_va << ", search for vertex " << index_vb << '\n';
|
||||
// for(auto it2 = it; it2 != end; ++it2) {
|
||||
// auto he = *it2;
|
||||
// auto vd = target(he, mesh);
|
||||
// std::cerr << " " << vd << '\n';
|
||||
// }
|
||||
it = std::find_if(it, end, [&mesh, index_vb](auto he) { return target(he, mesh) == index_vb; });
|
||||
CGAL_assertion(it != end);
|
||||
auto he = CGAL::Euler::split_edge(*it, mesh);
|
||||
auto mesh_v = target(he, mesh);
|
||||
put(pmap, mesh_v, v->point());
|
||||
assert(mesh_v == Vertex_index{static_cast<unsigned>(time_stamp - 1)});
|
||||
}
|
||||
// for(auto e: edges(mesh)) {
|
||||
// auto he = halfedge(e, mesh);
|
||||
// auto vd1 = target(he, mesh);
|
||||
// auto vd2 = source(he, mesh);
|
||||
// if(!get(v_selected_map, vd1) || !get(v_selected_map, vd2)) continue;
|
||||
// auto p1 = get(pmap, vd1);
|
||||
// auto p2 = get(pmap, vd2);
|
||||
// auto n = cdt.number_of_vertices();
|
||||
// auto v1 = cdt.insert(p1);
|
||||
// auto v2 = cdt.insert(p2);
|
||||
// CGAL_assertion(n == cdt.number_of_vertices());
|
||||
// auto steiner_vertices = cdt.sequence_of_Steiner_vertices(v1, v2);
|
||||
// if(!steiner_vertices) continue;
|
||||
// for(auto v: *steiner_vertices) {
|
||||
// he = CGAL::Euler::split_edge(he, mesh);
|
||||
// put(pmap, target(he, mesh), v->point());
|
||||
// }
|
||||
// }
|
||||
std::ofstream out_mesh(options.dump_after_conforming_filename);
|
||||
out_mesh.precision(17);
|
||||
out_mesh << mesh;
|
||||
out_mesh.close();
|
||||
CGAL_CDT_3_TASK_END(output_task_handle);
|
||||
}
|
||||
|
||||
if(!options.quiet) {
|
||||
std::cout << "Number of vertices after conforming: " << cdt.number_of_vertices() << "\n\n";
|
||||
}
|
||||
CGAL_CDT_3_TASK_BEGIN(validation_task_handle);
|
||||
CGAL_assertion(!options.call_is_valid || cdt.Base_triantulation::is_valid(true));
|
||||
CGAL_assertion(!options.call_is_valid || cdt.is_valid(true));
|
||||
CGAL_assertion(!options.call_is_valid || cdt.is_conforming());
|
||||
CGAL_CDT_3_TASK_END(validation_task_handle);
|
||||
if(exit_code == EXIT_SUCCESS) {
|
||||
try {
|
||||
CGAL_CDT_3_TASK_BEGIN(cdt_task_handle);
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
cdt.restore_constrained_Delaunay();
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] restored constrained Delaunay in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
std::cout << "Number of vertices after CDT: " << cdt.number_of_vertices() << "\n\n";
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(cdt_task_handle);
|
||||
} catch(int error) {
|
||||
exit_code = error;
|
||||
}
|
||||
}
|
||||
} CDT_3_catch(CGAL::Failure_exception&) {
|
||||
finally();
|
||||
CDT_3_throw_exception_again;
|
||||
}
|
||||
finally();
|
||||
|
||||
CGAL_CDT_3_TASK_BEGIN(validation_task_handle);
|
||||
CGAL_assertion(!options.call_is_valid || cdt.is_conforming());
|
||||
CGAL_assertion(!options.call_is_valid || cdt.is_valid(true));
|
||||
CGAL_CDT_3_TASK_END(validation_task_handle);
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int bissect_errors(Mesh mesh, CDT_options options) {
|
||||
auto nb_buckets = static_cast<int>(std::floor(1 / options.ratio)) + 1;
|
||||
std::cerr << "RATIO: " << options.ratio << '\n';
|
||||
|
||||
const Mesh orig_mesh{mesh};
|
||||
Mesh bad_mesh{mesh};
|
||||
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
|
||||
for(int bucket = 0; bucket < nb_buckets;) {
|
||||
const auto nb_faces = mesh.number_of_faces();
|
||||
auto nb_to_skip = static_cast<int>(std::round(nb_faces * options.ratio));
|
||||
if(nb_to_skip < 1) {
|
||||
nb_to_skip = 1;
|
||||
nb_buckets = nb_faces;
|
||||
}
|
||||
if(bucket == 0) {
|
||||
std::cerr << "NB BUCKETS: " << nb_buckets << '\n';
|
||||
}
|
||||
|
||||
auto simplify = [&](Mesh& m) {
|
||||
std::cerr << "nb_to_skip: " << nb_to_skip << '\n';
|
||||
std::cerr << "bucket: " << bucket << '\n';
|
||||
const auto start = (std::min)(bucket * nb_to_skip, static_cast<int>(m.number_of_faces()));
|
||||
const auto end = (std::min)(start + nb_to_skip, static_cast<int>(m.number_of_faces()));
|
||||
std::cerr << "SKIP from " << start << " to " << end << '\n';
|
||||
for(auto i = end - 1; i >= start; --i) {
|
||||
const auto f = m.faces().begin() + i;
|
||||
CGAL::Euler::remove_face(halfedge(*f, m), m);
|
||||
}
|
||||
assert(m.is_valid(true));
|
||||
std::cerr << "number of faces: " << m.number_of_faces() << '\n';
|
||||
if(m.number_of_faces() >= nb_faces) {
|
||||
std::cerr << "ERROR: could not simplify mesh\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
};
|
||||
|
||||
simplify(mesh);
|
||||
std::ofstream current("current_mesh.off");
|
||||
current.precision(17);
|
||||
current << mesh;
|
||||
current.close();
|
||||
|
||||
try {
|
||||
auto code = go(mesh, options);
|
||||
if(code != EXIT_SUCCESS) {
|
||||
exit_code = code;
|
||||
}
|
||||
} catch(CGAL::Failure_exception& e) {
|
||||
std::cerr << "CAUGHT EXCEPTION: " << e.what() << '\n';
|
||||
if(std::string(e.what()).find(options.failure_assertion_expression) != std::string::npos)
|
||||
{
|
||||
exit_code = EXIT_FAILURE;
|
||||
std::cerr << "BAD MESH! " << mesh.number_of_faces() << " faces\n";
|
||||
std::ofstream bad("bad_mesh.off");
|
||||
bad.precision(17);
|
||||
bad << mesh;
|
||||
bad_mesh = mesh;
|
||||
bucket = 0;
|
||||
continue;
|
||||
} else {
|
||||
exit_code = EXIT_FAILURE;
|
||||
std::cerr << "ERROR MESH: " << e.what() << '\n';
|
||||
std::ofstream error("error_mesh.off");
|
||||
error.precision(17);
|
||||
error << mesh;
|
||||
std::cerr << "go on...\n";
|
||||
}
|
||||
}
|
||||
std::cerr << "GOOD MESH :-( " << mesh.number_of_faces() << " faces\n";
|
||||
mesh = bad_mesh;
|
||||
++bucket;
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CDT::Conforming_Dt::with_offset.offset = -1;
|
||||
CDT::Conforming_Dt::with_point.offset = -1;
|
||||
CDT::Conforming_Dt::with_point_and_info.offset = -1;
|
||||
std::cerr.precision(17);
|
||||
std::cout.precision(17);
|
||||
|
||||
CDT_options options(argc, argv);
|
||||
if(options.need_help) {
|
||||
help(std::cout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CGAL_CDT_3_TASK_BEGIN(read_input_task_handle);
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto read_options = CGAL::parameters::repair_polygon_soup(options.repair_mesh).verbose(options.verbose_level);
|
||||
auto result = CGAL::read_polygon_mesh_for_cdt_3<Mesh>(options.input_filename, read_options);
|
||||
|
||||
if (!result.polygon_mesh)
|
||||
{
|
||||
std::cerr << "Not a valid input file." << std::endl;
|
||||
std::cerr << "Details:\n" << result.polygon_mesh.error() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Mesh mesh = std::move(*result.polygon_mesh);
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] read mesh in " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
std::cout << "Number of vertices: " << mesh.number_of_vertices() << '\n';
|
||||
std::cout << "Number of edges: " << mesh.number_of_edges() << '\n';
|
||||
std::cout << "Number of faces: " << mesh.number_of_faces() << "\n\n";
|
||||
|
||||
std::cout << "Processing was successful.\n";
|
||||
std::cout << " Number of duplicated points: " << result.nb_of_duplicated_points << '\n';
|
||||
std::cout << " Number of simplified polygons: " << result.nb_of_simplified_polygons << '\n';
|
||||
std::cout << " Number of new polygons: " << result.nb_of_new_polygons << '\n';
|
||||
std::cout << " Number of removed invalid polygons: " << result.nb_of_removed_invalid_polygons << '\n';
|
||||
std::cout << " Number of removed duplicated polygons: " << result.nb_of_removed_duplicated_polygons << '\n';
|
||||
std::cout << " Number of removed isolated points: " << result.nb_of_removed_isolated_points << '\n';
|
||||
std::cout << " Polygon soup self-intersects: " << (result.polygon_soup_self_intersects ? "YES" : "no") << '\n';
|
||||
std::cout << " Polygon mesh is manifold: " << (result.polygon_mesh_is_manifold ? "yes" : "NO") << '\n';
|
||||
std::cout << std::endl;
|
||||
}
|
||||
CGAL_CDT_3_TASK_END(read_input_task_handle);
|
||||
|
||||
if(options.reject_self_intersections && result.polygon_soup_self_intersects) {
|
||||
std::cerr << "ERROR: input mesh self-intersects\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(!options.failure_assertion_expression.empty()) {
|
||||
return bissect_errors(std::move(mesh), options);
|
||||
}
|
||||
|
||||
auto exit_code = go(std::move(mesh), options);
|
||||
if(!options.quiet) {
|
||||
std::cout << "[timings] total time: " << std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - start_time).count() << " ms\n";
|
||||
if(exit_code != 0) std::cout << "ERROR with exit code " << exit_code << '\n';
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define CGAL_CDT_3_USE_EPECK 1
|
||||
#include "cdt_3_from_off.cpp"
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#if __has_include(<format>)
|
||||
#define CGAL_DEBUG_CDT_3 1
|
||||
#endif
|
||||
#define CGAL_TRIANGULATION_CHECK_EXPENSIVE 1
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Conforming_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Triangulation_simplex_base_with_time_stamp.h>
|
||||
#include <CGAL/draw_triangulation_3.h>
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Triangulation_data_structure_3<
|
||||
CGAL::Triangulation_simplex_base_with_time_stamp<CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<K>>,
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<K> > Tds;
|
||||
typedef CGAL::Delaunay_triangulation_3<K, Tds> Delaunay;
|
||||
typedef Delaunay::Point Point;
|
||||
using Point_3 = K::Point_3;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr.precision(17);
|
||||
std::cout.precision(17);
|
||||
|
||||
auto test1 = []() {
|
||||
const std::vector<Point_3> points = { { -2, 0, 0 },
|
||||
{ 2, 0, 0 },
|
||||
{ 0, 1, -1 },
|
||||
{ 0, -1, -1 },
|
||||
{ 0, 0, 1 },
|
||||
{ -10, -10, -10 },
|
||||
{ -10, 10, -10 },
|
||||
{ 10, 10, -10 },
|
||||
{ 10, -10, -10 },
|
||||
{ -10, -10, 10 },
|
||||
{ -10, 10, 10 },
|
||||
{ 10, 10, 10 },
|
||||
{ 10, -10, 10 },
|
||||
};
|
||||
std::vector<Delaunay::Vertex_handle> vertices;
|
||||
vertices.reserve(points.size());
|
||||
CGAL::Conforming_Delaunay_triangulation_3<Delaunay> cdt;
|
||||
for(auto p: points) vertices.push_back(cdt.insert(p));
|
||||
Delaunay::Cell_handle c;
|
||||
assert( cdt.is_valid() );
|
||||
assert(cdt.is_cell(vertices[0], vertices[2], vertices[3], vertices[4], c));
|
||||
assert(cdt.is_cell(vertices[1], vertices[2], vertices[3], vertices[4], c));
|
||||
|
||||
Delaunay::Cell_handle ch;
|
||||
int li, lj;
|
||||
assert(!cdt.is_edge(vertices[0], vertices[1], ch, li, lj));
|
||||
cdt.insert_constrained_edge(vertices[0], vertices[1]);
|
||||
cdt.insert_constrained_edge(vertices[5], vertices[1]);
|
||||
cdt.insert_constrained_edge(vertices[5], vertices[10]);
|
||||
std::cerr << "test1: "
|
||||
<< (cdt.is_conforming() ? "OK" : "ERROR: NOT CONFORMING")
|
||||
<< std::endl;
|
||||
return cdt.is_conforming() ? 0 : 1;
|
||||
};
|
||||
|
||||
enum Dim { DIM_2D, DIM_3D };
|
||||
|
||||
auto test2 = [](std::string filename, Dim dim = DIM_3D) {
|
||||
#ifndef CGAL_TEST_CDT_3_USE_CDT
|
||||
CGAL::Conforming_Delaunay_triangulation_3<Delaunay> cdt;
|
||||
#else
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_3_impl<Delaunay> cdt;
|
||||
#endif
|
||||
|
||||
std::ifstream input(filename);
|
||||
if(!input) throw "file not found";
|
||||
int n;
|
||||
input >> n;
|
||||
std::cerr << n << " lines in the file\n";
|
||||
while(n-- > 0) {
|
||||
double x, y;
|
||||
input >> x >> y;
|
||||
auto v1 = cdt.insert({x, y, 0}), v3 = v1;
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
if(dim == DIM_3D) {
|
||||
v3 = cdt.insert({x, y, 1});
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
}
|
||||
input >> x >> y;
|
||||
auto v2 = cdt.insert({x, y, 0}), v4 = v1;
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
if(dim == DIM_3D) {
|
||||
v4 = cdt.insert({x, y, 1});
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
}
|
||||
cdt.insert_constrained_edge(v1, v2);
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
if(dim == DIM_3D) {
|
||||
cdt.insert_constrained_edge(v3, v4);
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
}
|
||||
}
|
||||
cdt.insert({11, 28, 0});
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
cdt.insert({11, 33, 0});
|
||||
CGAL_assertion(cdt.is_conforming());
|
||||
|
||||
for (auto v : cdt.finite_vertex_handles()) {
|
||||
std::cout << "Point ( " << v->point() << " )\n";
|
||||
std::cout << " on " << v->ccdt_3_data().number_of_incident_constraints()
|
||||
<< " constraint(s)\n";
|
||||
}
|
||||
std::cerr << "test2: " << filename << " "
|
||||
<< (cdt.is_conforming() ? "OK" : "ERROR: NOT CONFORMING")
|
||||
<< std::endl;
|
||||
return cdt.is_conforming() ? 0 : 1;
|
||||
};
|
||||
|
||||
return test1() + test2(CGAL::data_file_path("2d_segments/clusters.edg")) +
|
||||
test2(CGAL::data_file_path("2d_segments/clusters2.edg"))
|
||||
// // For the moment, Triangulation_segment_traverser_3 does not work in 1D:
|
||||
// // Expr: _tr->dimension() >= 2
|
||||
// // File: .../CGAL/Triangulation_3/internal/Triangulation_segment_traverser_3_impl.h
|
||||
// + test2(CGAL::data_file_path("2d_segments/clusters.edg"), DIM_2D) +
|
||||
// test2(CGAL::data_file_path("2d_segments/clusters2.edg"), DIM_2D)
|
||||
;
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#if __has_include(<format>)
|
||||
#define CGAL_DEBUG_CDT_3 1
|
||||
#endif
|
||||
#define CGAL_TRIANGULATION_CHECK_EXPENSIVE 1
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Conforming_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/IO/File_binary_mesh_3.h>
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Triangulation_data_structure_3<
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<K>,
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<K> > Tds;
|
||||
typedef CGAL::Delaunay_triangulation_3<K, Tds> Delaunay;
|
||||
typedef Delaunay::Point Point;
|
||||
using Point_3 = K::Point_3;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Mesh;
|
||||
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cerr.precision(17);
|
||||
std::cout.precision(17);
|
||||
|
||||
const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/fandisk.off");
|
||||
std::ifstream input(filename);
|
||||
Mesh mesh;
|
||||
if (!input || !(input >> mesh))
|
||||
{
|
||||
std::cerr << "Not a valid input file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CGAL_TEST_CDT_3_USE_CDT
|
||||
CGAL::Conforming_Delaunay_triangulation_3<Delaunay> cdt_edge;
|
||||
#else
|
||||
CGAL::Conforming_constrained_Delaunay_triangulation_3_impl<Delaunay> cdt_edge;
|
||||
#endif
|
||||
auto point_map = get(CGAL::vertex_point, mesh);
|
||||
auto dt_vertex_handle_map =
|
||||
get(CGAL::dynamic_vertex_property_t<Delaunay::Vertex_handle>(), mesh);
|
||||
for(auto vertex_descriptor: vertices(mesh)) {
|
||||
auto vertex_handle = cdt_edge.insert(get(point_map, vertex_descriptor));
|
||||
put(dt_vertex_handle_map, vertex_descriptor, vertex_handle);
|
||||
}
|
||||
|
||||
for(auto edge_descriptor: edges(mesh)) {
|
||||
auto s = source(edge_descriptor, mesh);
|
||||
auto t = target(edge_descriptor, mesh);
|
||||
cdt_edge.insert_constrained_edge(get(dt_vertex_handle_map, s),
|
||||
get(dt_vertex_handle_map, t));
|
||||
}
|
||||
{
|
||||
std::ofstream all_edges("all_segments.polylines.txt");
|
||||
all_edges.precision(17);
|
||||
cdt_edge.write_all_segments_file(all_edges);
|
||||
}
|
||||
assert(cdt_edge.is_conforming());
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
OFF
|
||||
13 5 0
|
||||
|
||||
76.621499999999997 42.272500000000001 20.489999999999998
|
||||
76.621499999999997 32.026499999999999 20.489999999999998
|
||||
69.537490000000005 35.112499999999997 9.218
|
||||
67.6845 38.579500000000003 9.218
|
||||
67.6845 38.579500000000003 51.222000000000001
|
||||
70.869500000000002 32.25582 49.106000000000002
|
||||
70.869500000000002 48.061500000000002 49.106000000000002
|
||||
70.869500000000002 48.061500000000002 1.522
|
||||
70.869500000000002 32.25582 3
|
||||
-50.930500000000002 48.061500000000002 51.220999999999997
|
||||
-50.930500000000002 29.410250000000001 51.220999999999997
|
||||
-50.930500000000002 29.410250000000001 51.222000000000001
|
||||
71.505499999999998 42.272500000000001 20.489999999999998
|
||||
3 5 6 8
|
||||
3 7 8 6
|
||||
3 1 12 0
|
||||
3 9 10 11
|
||||
3 4 3 2
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
OFF
|
||||
24 9 0
|
||||
|
||||
29.177140000000001 -11.9015 9.3190000000000008
|
||||
27.660139999999998 -4.4725000000000001 0.90100000000000002
|
||||
27.605139999999999 -4.9975009999999997 1.1890000000000001
|
||||
29.287140000000001 -10.8515 8.7420000000000009
|
||||
30.858139999999999 -17.755500000000001 16.872
|
||||
27.550139999999999 -5.5225010000000001 1.478
|
||||
26.892140000000001 -4.7785000000000002 9.4410000000000007
|
||||
32.57414 -18.9375 9.6549990000000001
|
||||
28.742139999999999 -7.0465010000000001 1.536
|
||||
33.624940000000002 -19.21181 1.719867
|
||||
33.155610000000003 -19.64996 7.1717440000000003
|
||||
33.073520000000002 -19.726600000000001 10.307399999999999
|
||||
27.64414 -6.1995009999999997 10.102
|
||||
29.494140000000002 -8.4675010000000004 2.1970000000000001
|
||||
23.812139999999999 5.6904979999999998 1.9830000000000001
|
||||
23.883120000000002 7.817234 1.031652
|
||||
24.546140000000001 8.5294989999999995 0.81284809999999996
|
||||
24.546600000000002 8.5283010000000008 0.81257199999999996
|
||||
34.17239 -18.798279999999998 3.65543
|
||||
-5.1928599999999996 17.827500000000001 10.176
|
||||
31.518650000000001 -13.5115 2.2735919999999998
|
||||
28.742139999999999 -7.0465010000000001 1.536
|
||||
27.64414 -6.1995009999999997 10.102
|
||||
23.418150000000001 7.948887 18.369129999999998
|
||||
3 1 2 3
|
||||
3 3 2 4
|
||||
3 2 5 0
|
||||
3 8 7 6
|
||||
3 21 9 10
|
||||
3 11 20 12
|
||||
3 13 14 22
|
||||
3 23 18 15
|
||||
3 19 16 17
|
||||
|
||||
|
|
@ -0,0 +1,627 @@
|
|||
OFF
|
||||
317 306 0
|
||||
|
||||
-93.417749999999998 104.5005 23.143540000000002
|
||||
-93.397530000000003 104.955 23.335920000000002
|
||||
-93.379499999999993 105.4179 23.50742
|
||||
-93.363709999999998 105.88809999999999 23.657689999999999
|
||||
-93.350179999999995 106.3648 23.786429999999999
|
||||
-93.338939999999994 106.84690000000001 23.893350000000002
|
||||
-93.330020000000005 107.3334 23.97824
|
||||
-93.323430000000002 107.8233 24.04092
|
||||
-93.319190000000006 108.3156 24.08126
|
||||
-93.317310000000006 108.8092 24.099170000000001
|
||||
-93.317790000000002 109.3031 24.094609999999999
|
||||
-93.320629999999994 109.7963 24.067599999999999
|
||||
-93.325819999999993 110.2877 24.018190000000001
|
||||
-93.333359999999999 110.7764 23.946490000000001
|
||||
-93.343220000000002 111.2612 23.852640000000001
|
||||
-93.35539 111.74120000000001 23.736840000000001
|
||||
-93.369839999999996 112.2154 23.599329999999998
|
||||
-93.38655 112.6828 23.44041
|
||||
-93.405469999999994 113.14239999999999 23.260400000000001
|
||||
-93.426559999999995 113.5932 23.059670000000001
|
||||
-93.449789999999993 114.0343 22.838660000000001
|
||||
-93.475110000000001 114.4648 22.597819999999999
|
||||
-93.502449999999996 114.88379999999999 22.33766
|
||||
-93.531769999999995 115.29040000000001 22.058710000000001
|
||||
-93.563000000000002 115.6837 21.761569999999999
|
||||
-93.596080000000001 116.063 21.446860000000001
|
||||
-93.630930000000006 116.42740000000001 21.115220000000001
|
||||
-93.667500000000004 116.7761 20.76737
|
||||
-93.705690000000004 117.1086 20.404019999999999
|
||||
-93.745419999999996 117.4239 20.025929999999999
|
||||
-93.786630000000002 117.7216 19.633900000000001
|
||||
-93.829210000000003 118.0009 19.228739999999998
|
||||
-93.873090000000005 118.2612 18.811309999999999
|
||||
-93.91816 118.5022 18.382470000000001
|
||||
-93.964330000000004 118.7231 17.94313
|
||||
-94.011520000000004 118.9237 17.494199999999999
|
||||
-94.059610000000006 119.1033 17.036619999999999
|
||||
-94.108519999999999 119.26179999999999 16.571339999999999
|
||||
-94.158119999999997 119.39870000000001 16.099350000000001
|
||||
-94.208330000000004 119.5137 15.62163
|
||||
-94.259039999999999 119.6067 15.13917
|
||||
-94.310140000000004 119.67740000000001 14.653
|
||||
-94.361530000000002 119.7256 14.164110000000001
|
||||
-94.413089999999997 119.7514 13.673550000000001
|
||||
-94.46472 119.75449999999999 13.182320000000001
|
||||
-94.516310000000004 119.7351 12.691470000000001
|
||||
-94.567750000000004 119.6931 12.20201
|
||||
-94.618939999999995 119.62869999999999 11.714969999999999
|
||||
-94.66977 119.5419 11.23138
|
||||
-94.720129999999997 119.43300000000001 10.752230000000001
|
||||
-94.769919999999999 119.3022 10.27854
|
||||
-94.819029999999998 119.1497 9.8112899999999996
|
||||
-94.867360000000005 118.976 9.3514630000000007
|
||||
-94.9148 118.7812 8.9000199999999996
|
||||
-94.961269999999999 118.5659 8.4579029999999999
|
||||
-95.006659999999997 118.3305 8.0260400000000001
|
||||
-95.050880000000006 118.07550000000001 7.6053319999999998
|
||||
-95.093829999999997 117.8015 7.1966590000000004
|
||||
-95.135429999999999 117.5089 6.8008769999999998
|
||||
-95.17559 117.19840000000001 6.4188140000000002
|
||||
-95.214219999999997 116.8707 6.0512680000000003
|
||||
-95.251239999999996 116.5264 5.6990080000000001
|
||||
-95.286580000000001 116.16630000000001 5.3627710000000004
|
||||
-95.320170000000005 115.7911 5.0432610000000002
|
||||
-95.351920000000007 115.40170000000001 4.7411459999999996
|
||||
-95.381780000000006 114.9987 4.4570569999999998
|
||||
-95.409679999999994 114.5831 4.1915899999999997
|
||||
-95.435569999999998 114.1557 3.9452980000000002
|
||||
-95.459379999999996 113.7175 3.7186979999999998
|
||||
-95.481080000000006 113.2693 3.5122640000000001
|
||||
-95.500609999999995 112.812 3.3264260000000001
|
||||
-95.517939999999996 112.3467 3.161575
|
||||
-95.533019999999993 111.87439999999999 3.0180539999999998
|
||||
-95.545829999999995 111.3959 2.8961640000000002
|
||||
-95.556349999999995 110.9123 2.79616
|
||||
-95.564530000000005 110.4246 2.718251
|
||||
-95.57038 109.93380000000001 2.6625999999999999
|
||||
-95.573880000000003 109.441 2.629324
|
||||
-95.575019999999995 108.9472 2.6184919999999998
|
||||
-95.573800000000006 108.4534 2.6301260000000002
|
||||
-95.570210000000003 107.9606 2.6642030000000001
|
||||
-95.564279999999997 107.47 2.72065
|
||||
-95.556010000000001 106.9824 2.7993510000000001
|
||||
-95.545419999999993 106.499 2.9001399999999999
|
||||
-93.470569999999995 104.8374 22.641030000000001
|
||||
-93.673500000000004 101.9252 20.71021
|
||||
-93.620689999999996 101.5883 21.212730000000001
|
||||
-94.495990000000006 98.166550000000001 12.8848
|
||||
-94.444649999999996 98.156009999999995 13.373200000000001
|
||||
-94.393320000000003 98.167820000000006 13.86158
|
||||
-94.342100000000002 98.201939999999993 14.34891
|
||||
-94.2911 98.258309999999994 14.834199999999999
|
||||
-94.240409999999997 98.33681 15.31644
|
||||
-94.190150000000003 98.437269999999998 15.79463
|
||||
-94.140420000000006 98.559489999999997 16.267779999999998
|
||||
-94.091319999999996 98.703220000000002 16.734909999999999
|
||||
-94.042959999999994 98.868160000000003 17.195060000000002
|
||||
-93.995429999999999 99.053970000000007 17.647279999999999
|
||||
-93.948830000000001 99.260260000000002 18.090620000000001
|
||||
-93.903260000000003 99.486609999999999 18.524180000000001
|
||||
-93.858819999999994 99.73254 18.94706
|
||||
-93.81559 99.997559999999993 19.35838
|
||||
-93.773660000000007 100.2811 19.757280000000002
|
||||
-93.73312 100.5826 20.142949999999999
|
||||
-93.694059999999993 100.9014 20.514589999999998
|
||||
-93.656559999999999 101.23690000000001 20.87143
|
||||
-94.480429999999998 98.836250000000007 13.03281
|
||||
-94.850300000000004 99.622569999999996 9.5137219999999996
|
||||
-94.866339999999994 98.932140000000004 9.3611330000000006
|
||||
-95.51737 105.5489 3.166982
|
||||
-95.499979999999994 105.0842 3.332446
|
||||
-95.48039 104.6276 3.518853
|
||||
-95.458629999999999 104.18000000000001 3.7258140000000002
|
||||
-95.43477 103.7424 3.952896
|
||||
-95.408839999999998 103.31570000000001 4.1996250000000002
|
||||
-95.380889999999994 102.9008 4.4654850000000001
|
||||
-95.350999999999999 102.49850000000001 4.7499219999999998
|
||||
-95.319209999999998 102.1097 5.0523410000000002
|
||||
-95.285600000000002 101.73520000000001 5.3721110000000003
|
||||
-95.250240000000005 101.3758 5.708564
|
||||
-95.213200000000001 101.0322 6.0609960000000003
|
||||
-95.174549999999996 100.7052 6.4286729999999999
|
||||
-95.134389999999996 100.3954 6.8108250000000004
|
||||
-95.092780000000005 100.1035 7.2066549999999996
|
||||
-95.04983 99.830100000000002 7.6153360000000001
|
||||
-95.005610000000004 99.575739999999996 8.0360139999999998
|
||||
-94.960229999999996 99.340980000000002 8.4678120000000003
|
||||
-94.91377 99.126289999999997 8.9098249999999997
|
||||
-94.808099999999996 95.907730000000001 9.9152629999999995
|
||||
-94.86336 96.059650000000005 9.3894450000000003
|
||||
-94.917940000000002 96.232979999999998 8.8702179999999995
|
||||
-94.971729999999994 96.427440000000004 8.3584460000000007
|
||||
-95.024640000000005 96.642700000000005 7.8549769999999999
|
||||
-95.076599999999999 96.878410000000002 7.3606480000000003
|
||||
-95.127510000000001 97.134169999999997 6.8762800000000004
|
||||
-95.177289999999999 97.409559999999999 6.4026759999999996
|
||||
-95.225849999999994 97.704120000000003 5.9406239999999997
|
||||
-95.273120000000006 98.01737 5.4908900000000003
|
||||
-95.319010000000006 98.348780000000005 5.0542210000000001
|
||||
-95.363460000000003 98.697800000000001 4.6313430000000002
|
||||
-95.406379999999999 99.063850000000002 4.2229570000000001
|
||||
-95.447710000000001 99.446340000000006 3.8297409999999998
|
||||
-95.487380000000002 99.844610000000003 3.4523489999999999
|
||||
-95.525310000000005 100.258 3.0914069999999998
|
||||
-95.561459999999997 100.6858 2.7475139999999998
|
||||
-95.595749999999995 101.12739999999999 2.4212419999999999
|
||||
-95.628129999999999 101.58199999999999 2.1131319999999998
|
||||
-95.658559999999994 102.0488 1.823696
|
||||
-95.686959999999999 102.5271 1.5534140000000001
|
||||
-95.713310000000007 103.01609999999999 1.3027359999999999
|
||||
-95.737549999999999 103.5149 1.0720769999999999
|
||||
-95.759649999999993 104.0228 0.86182000000000003
|
||||
-95.779570000000007 104.53879999999999 0.67231490000000005
|
||||
-95.797269999999997 105.0622 0.50387599999999999
|
||||
-95.812730000000002 105.592 0.35678300000000002
|
||||
-95.82593 106.1275 0.23128019999999999
|
||||
-94.773200000000003 97.409880000000001 10.24724
|
||||
-94.660960000000003 97.171260000000004 11.31517
|
||||
-94.695849999999993 95.669110000000003 10.98319
|
||||
-93.304839999999999 101.01609999999999 24.217780000000001
|
||||
-93.338939999999994 100.5859 23.893339999999998
|
||||
-93.374809999999997 100.169 23.552040000000002
|
||||
-93.412400000000005 99.766229999999993 23.19444
|
||||
-93.451639999999998 99.378129999999999 22.821110000000001
|
||||
-93.492469999999997 99.005350000000007 22.432639999999999
|
||||
-93.534819999999996 98.648489999999995 22.02966
|
||||
-93.578639999999993 98.308120000000002 21.61281
|
||||
-93.623840000000001 97.984780000000001 21.182749999999999
|
||||
-93.670349999999999 97.678989999999999 20.740179999999999
|
||||
-93.718109999999996 97.391239999999996 20.285799999999998
|
||||
-93.767030000000005 97.121989999999997 19.820350000000001
|
||||
-93.817040000000006 96.871669999999995 19.344560000000001
|
||||
-93.868049999999997 96.640680000000003 18.859190000000002
|
||||
-93.919989999999999 96.429389999999998 18.365020000000001
|
||||
-93.972769999999997 96.238140000000001 17.862850000000002
|
||||
-94.026309999999995 96.067229999999995 17.353470000000002
|
||||
-94.080520000000007 95.916939999999997 16.837710000000001
|
||||
-94.135310000000004 95.787509999999997 16.316379999999999
|
||||
-94.190600000000003 95.679150000000007 15.790319999999999
|
||||
-94.246300000000005 95.592020000000005 15.26037
|
||||
-94.302319999999995 95.526269999999997 14.72738
|
||||
-94.35857 95.482010000000002 14.1922
|
||||
-94.414959999999994 95.459299999999999 13.65569
|
||||
-94.471400000000003 95.458169999999996 13.1187
|
||||
-94.527799999999999 95.478639999999999 12.582100000000001
|
||||
-94.584069999999997 95.520669999999996 12.046749999999999
|
||||
-94.640119999999996 95.584199999999996 11.513489999999999
|
||||
-93.438680000000005 101.86969999999999 22.94444
|
||||
-94.369420000000005 102.785 23.655799999999999
|
||||
-93.374899999999997 102.785 23.551269999999999
|
||||
-94.235579999999999 101.9314 24.92914
|
||||
-93.241060000000004 101.9314 24.82461
|
||||
-95.845389999999995 107.2098 0.046065479999999999
|
||||
-95.851650000000006 107.75490000000001 -0.01347809
|
||||
-95.855590000000007 108.30200000000001 -0.050956609999999999
|
||||
-95.857200000000006 108.8501 -0.066308259999999994
|
||||
-95.856489999999994 109.3985 -0.059507690000000002
|
||||
-95.853449999999995 109.9461 -0.030566139999999999
|
||||
-95.848079999999996 110.492 0.020468650000000001
|
||||
-95.840410000000006 111.0355 0.09351247
|
||||
-95.830430000000007 111.57550000000001 0.1884448
|
||||
-95.818169999999995 112.11109999999999 0.30510900000000002
|
||||
-95.803640000000001 112.6416 0.4433126
|
||||
-95.786869999999993 113.166 0.60282749999999996
|
||||
-95.767899999999997 113.6835 0.78339049999999999
|
||||
-95.746740000000003 114.1931 0.98470380000000002
|
||||
-95.723429999999993 114.69410000000001 1.2064349999999999
|
||||
-95.69802 115.18559999999999 1.4482189999999999
|
||||
-95.670540000000003 115.6669 1.7096549999999999
|
||||
-95.641040000000004 116.1371 1.9903139999999999
|
||||
-95.609570000000005 116.5954 2.2897310000000002
|
||||
-95.576179999999994 117.0411 2.6074139999999999
|
||||
-95.540930000000003 117.4735 2.9428359999999998
|
||||
-95.503870000000006 117.89190000000001 3.2954460000000001
|
||||
-95.465059999999994 118.2955 3.6646619999999999
|
||||
-95.424570000000003 118.6836 4.0498729999999998
|
||||
-95.382469999999998 119.0558 4.4504450000000002
|
||||
-95.338830000000002 119.41119999999999 4.8657159999999999
|
||||
-95.293710000000004 119.74939999999999 5.2950020000000002
|
||||
-95.247190000000003 120.0698 5.7375939999999996
|
||||
-95.199349999999995 120.3719 6.1927620000000001
|
||||
-95.150270000000006 120.6551 6.6597549999999996
|
||||
-95.100020000000001 120.9191 7.1378019999999998
|
||||
-95.048699999999997 121.16330000000001 7.6261140000000003
|
||||
-94.996380000000002 121.3873 8.1238860000000006
|
||||
-94.943150000000003 121.5908 8.6302970000000006
|
||||
-94.889110000000002 121.7735 9.1445100000000004
|
||||
-94.834329999999994 121.93510000000001 9.6656779999999998
|
||||
-94.778909999999996 122.0752 10.19294
|
||||
-94.722949999999997 122.19370000000001 10.725429999999999
|
||||
-94.666520000000006 122.2903 11.262259999999999
|
||||
-94.609740000000002 122.36490000000001 11.80255
|
||||
-94.552679999999995 122.4175 12.345409999999999
|
||||
-94.495450000000005 122.4478 12.889950000000001
|
||||
-94.438130000000001 122.4558 13.43526
|
||||
-94.380830000000003 122.44159999999999 13.98044
|
||||
-94.323639999999997 122.4051 14.5246
|
||||
-94.266649999999998 122.3464 15.066839999999999
|
||||
-94.209950000000006 122.26560000000001 15.606249999999999
|
||||
-94.153639999999996 122.16289999999999 16.141970000000001
|
||||
-94.097819999999999 122.03830000000001 16.673089999999998
|
||||
-94.042569999999998 121.8922 17.198740000000001
|
||||
-93.987989999999996 121.7248 17.718060000000001
|
||||
-93.934160000000006 121.5363 18.230180000000001
|
||||
-93.881180000000001 121.327 18.734269999999999
|
||||
-93.829130000000006 121.0973 19.229489999999998
|
||||
-93.778099999999995 120.8476 19.715019999999999
|
||||
-93.728170000000006 120.5782 20.190069999999999
|
||||
-93.679429999999996 120.2897 20.653849999999998
|
||||
-93.631950000000003 119.9825 21.105589999999999
|
||||
-93.585809999999995 119.657 21.544550000000001
|
||||
-93.541089999999997 119.31399999999999 21.969999999999999
|
||||
-93.497870000000006 118.9538 22.381250000000001
|
||||
-93.456209999999999 118.5771 22.777609999999999
|
||||
-93.416179999999997 118.1846 23.158429999999999
|
||||
-93.377859999999998 117.77679999999999 23.52308
|
||||
-93.341290000000001 117.3545 23.87096
|
||||
-93.306550000000001 116.9183 24.201499999999999
|
||||
-93.273690000000002 116.46899999999999 24.514150000000001
|
||||
-93.242769999999993 116.0073 24.808389999999999
|
||||
-93.213830000000002 115.53400000000001 25.083739999999999
|
||||
-93.186920000000001 115.0498 25.339749999999999
|
||||
-93.162090000000006 114.55549999999999 25.575990000000001
|
||||
-93.139380000000003 114.05200000000001 25.792069999999999
|
||||
-93.118819999999999 113.5401 25.987629999999999
|
||||
-93.100459999999998 113.02070000000001 26.16236
|
||||
-93.084310000000002 112.4945 26.31597
|
||||
-93.070419999999999 111.96250000000001 26.4482
|
||||
-93.058790000000002 111.4255 26.55883
|
||||
-93.049449999999993 110.8845 26.647680000000001
|
||||
-93.042420000000007 110.3402 26.71461
|
||||
-93.037700000000001 109.7937 26.759499999999999
|
||||
-93.035300000000007 109.2458 26.78228
|
||||
-93.035240000000002 108.69750000000001 26.782910000000001
|
||||
-93.037499999999994 108.1495 26.761389999999999
|
||||
-93.042079999999999 107.60290000000001 26.717759999999998
|
||||
-93.048990000000003 107.0585 26.652090000000001
|
||||
-94.052719999999994 106.51730000000001 26.66901
|
||||
-93.058189999999996 106.51730000000001 26.56448
|
||||
-94.064210000000003 105.98 26.559619999999999
|
||||
-93.069689999999994 105.98 26.455089999999998
|
||||
-94.077979999999997 105.4477 26.428619999999999
|
||||
-93.083460000000002 105.4477 26.324090000000002
|
||||
-94.093999999999994 104.9212 26.276230000000002
|
||||
-93.09948 104.9212 26.171700000000001
|
||||
-94.11224 104.40130000000001 26.102689999999999
|
||||
-93.117720000000006 104.40130000000001 25.998159999999999
|
||||
-94.132670000000005 103.889 25.90831
|
||||
-93.138149999999996 103.889 25.80378
|
||||
-94.155259999999998 103.38500000000001 25.693390000000001
|
||||
-93.160740000000004 103.38500000000001 25.58886
|
||||
-94.179969999999997 102.89019999999999 25.458290000000002
|
||||
-93.185450000000003 102.89019999999999 25.353760000000001
|
||||
-94.206760000000003 102.4054 25.203399999999998
|
||||
-93.212239999999994 102.4054 25.098870000000002
|
||||
-91.899990000000003 108.2647 15.10216
|
||||
-92.003979999999999 108.9357 14.112769999999999
|
||||
-90.723889999999997 108.37649999999999 14.81183
|
||||
-93.649770000000004 97.736189999999993 30.981169999999999
|
||||
-94.384450000000001 102.477 23.99109
|
||||
-93.290480000000002 102.477 23.876110000000001
|
||||
-97.412790000000001 106.3109 16.703620000000001
|
||||
-97.433499999999995 106.1067 16.506550000000001
|
||||
-96.418270000000007 106.3109 16.59909
|
||||
-98.297569999999993 106.59399999999999 30.28905
|
||||
-98.127359999999996 104.13160000000001 31.908560000000001
|
||||
-98.149199999999993 103.937 31.70072
|
||||
-98.172439999999995 103.7578 31.479600000000001
|
||||
-98.196960000000004 103.595 31.24634
|
||||
-98.222629999999995 103.44929999999999 31.002120000000001
|
||||
-98.249319999999997 103.3215 30.748180000000001
|
||||
-97.954170000000005 105.7884 33.556330000000003
|
||||
-97.93383 105.9974 33.749839999999999
|
||||
-95.532520000000005 106.02070000000001 3.0228069999999998
|
||||
-95.532520000000005 106.02070000000001 3.0228069999999998
|
||||
-95.836820000000003 106.66759999999999 0.12757579999999999
|
||||
-95.836820000000003 106.66759999999999 0.12757579999999999
|
||||
3 276 277 278
|
||||
3 278 279 280
|
||||
3 280 281 282
|
||||
3 282 283 284
|
||||
3 284 285 286
|
||||
3 286 287 288
|
||||
3 288 289 290
|
||||
3 290 291 292
|
||||
3 292 293 294
|
||||
3 192 81 316
|
||||
3 192 80 81
|
||||
3 192 193 80
|
||||
3 80 193 79
|
||||
3 79 193 194
|
||||
3 195 79 194
|
||||
3 195 78 79
|
||||
3 195 196 78
|
||||
3 78 196 77
|
||||
3 77 196 197
|
||||
3 76 197 198
|
||||
3 75 198 199
|
||||
3 74 199 200
|
||||
3 73 200 201
|
||||
3 72 201 202
|
||||
3 71 202 203
|
||||
3 204 71 203
|
||||
3 204 70 71
|
||||
3 204 205 70
|
||||
3 70 205 69
|
||||
3 69 205 206
|
||||
3 68 206 207
|
||||
3 67 207 208
|
||||
3 66 208 209
|
||||
3 65 209 210
|
||||
3 64 210 211
|
||||
3 63 211 212
|
||||
3 213 63 212
|
||||
3 213 62 63
|
||||
3 213 214 62
|
||||
3 62 214 61
|
||||
3 61 214 215
|
||||
3 60 215 216
|
||||
3 59 216 217
|
||||
3 58 217 218
|
||||
3 57 218 219
|
||||
3 56 219 220
|
||||
3 55 220 221
|
||||
3 222 55 221
|
||||
3 222 54 55
|
||||
3 222 223 54
|
||||
3 54 223 53
|
||||
3 53 223 224
|
||||
3 52 224 225
|
||||
3 51 225 226
|
||||
3 50 226 227
|
||||
3 49 227 228
|
||||
3 48 228 229
|
||||
3 47 229 230
|
||||
3 231 47 230
|
||||
3 231 46 47
|
||||
3 231 232 46
|
||||
3 46 232 45
|
||||
3 45 232 233
|
||||
3 44 233 234
|
||||
3 43 234 235
|
||||
3 42 235 236
|
||||
3 41 236 237
|
||||
3 40 237 238
|
||||
3 239 40 238
|
||||
3 239 39 40
|
||||
3 239 240 39
|
||||
3 39 240 38
|
||||
3 38 240 241
|
||||
3 37 241 242
|
||||
3 36 242 243
|
||||
3 35 243 244
|
||||
3 34 244 245
|
||||
3 33 245 246
|
||||
3 32 246 247
|
||||
3 248 32 247
|
||||
3 248 31 32
|
||||
3 248 249 31
|
||||
3 31 249 30
|
||||
3 30 249 250
|
||||
3 29 250 251
|
||||
3 28 251 252
|
||||
3 27 252 253
|
||||
3 26 253 254
|
||||
3 25 254 255
|
||||
3 24 255 256
|
||||
3 257 24 256
|
||||
3 257 23 24
|
||||
3 257 258 23
|
||||
3 23 258 22
|
||||
3 22 258 259
|
||||
3 21 259 260
|
||||
3 20 260 261
|
||||
3 19 261 262
|
||||
3 18 262 263
|
||||
3 17 263 264
|
||||
3 16 264 265
|
||||
3 266 16 265
|
||||
3 266 15 16
|
||||
3 266 267 15
|
||||
3 15 267 14
|
||||
3 14 267 268
|
||||
3 13 268 269
|
||||
3 12 269 270
|
||||
3 11 270 271
|
||||
3 10 271 272
|
||||
3 9 272 273
|
||||
3 8 273 274
|
||||
3 275 8 274
|
||||
3 275 7 8
|
||||
3 275 276 7
|
||||
3 7 276 6
|
||||
3 6 276 278
|
||||
3 5 278 280
|
||||
3 4 280 282
|
||||
3 3 282 284
|
||||
3 2 284 286
|
||||
3 1 286 288
|
||||
3 0 288 290
|
||||
3 189 290 292
|
||||
3 294 189 292
|
||||
3 294 191 189
|
||||
3 77 197 76
|
||||
3 76 198 75
|
||||
3 75 199 74
|
||||
3 74 200 73
|
||||
3 73 201 72
|
||||
3 72 202 71
|
||||
3 69 206 68
|
||||
3 68 207 67
|
||||
3 67 208 66
|
||||
3 66 209 65
|
||||
3 65 210 64
|
||||
3 64 211 63
|
||||
3 61 215 60
|
||||
3 60 216 59
|
||||
3 59 217 58
|
||||
3 58 218 57
|
||||
3 57 219 56
|
||||
3 56 220 55
|
||||
3 53 224 52
|
||||
3 52 225 51
|
||||
3 51 226 50
|
||||
3 50 227 49
|
||||
3 49 228 48
|
||||
3 48 229 47
|
||||
3 45 233 44
|
||||
3 44 234 43
|
||||
3 43 235 42
|
||||
3 42 236 41
|
||||
3 41 237 40
|
||||
3 38 241 37
|
||||
3 37 242 36
|
||||
3 36 243 35
|
||||
3 35 244 34
|
||||
3 34 245 33
|
||||
3 33 246 32
|
||||
3 30 250 29
|
||||
3 29 251 28
|
||||
3 28 252 27
|
||||
3 27 253 26
|
||||
3 26 254 25
|
||||
3 25 255 24
|
||||
3 22 259 21
|
||||
3 21 260 20
|
||||
3 20 261 19
|
||||
3 19 262 18
|
||||
3 18 263 17
|
||||
3 17 264 16
|
||||
3 14 268 13
|
||||
3 13 269 12
|
||||
3 12 270 11
|
||||
3 11 271 10
|
||||
3 10 272 9
|
||||
3 9 273 8
|
||||
3 6 278 5
|
||||
3 5 280 4
|
||||
3 4 282 3
|
||||
3 3 284 2
|
||||
3 2 286 1
|
||||
3 1 288 0
|
||||
3 0 290 189
|
||||
3 84 189 85
|
||||
3 84 0 189
|
||||
3 85 189 86
|
||||
3 86 189 187
|
||||
3 162 187 161
|
||||
3 162 86 187
|
||||
3 162 163 86
|
||||
3 86 163 105
|
||||
3 105 163 164
|
||||
3 104 164 165
|
||||
3 103 165 166
|
||||
3 102 166 167
|
||||
3 101 167 168
|
||||
3 100 168 169
|
||||
3 99 169 170
|
||||
3 171 99 170
|
||||
3 171 98 99
|
||||
3 171 172 98
|
||||
3 98 172 97
|
||||
3 97 172 173
|
||||
3 96 173 174
|
||||
3 95 174 175
|
||||
3 94 175 176
|
||||
3 93 176 177
|
||||
3 92 177 178
|
||||
3 179 92 178
|
||||
3 179 91 92
|
||||
3 179 180 91
|
||||
3 91 180 90
|
||||
3 90 180 181
|
||||
3 89 181 182
|
||||
3 88 182 183
|
||||
3 87 183 184
|
||||
3 157 184 185
|
||||
3 186 157 185
|
||||
3 186 158 157
|
||||
3 159 160 187
|
||||
3 187 160 161
|
||||
3 105 164 104
|
||||
3 104 165 103
|
||||
3 103 166 102
|
||||
3 102 167 101
|
||||
3 101 168 100
|
||||
3 100 169 99
|
||||
3 97 173 96
|
||||
3 96 174 95
|
||||
3 95 175 94
|
||||
3 94 176 93
|
||||
3 93 177 92
|
||||
3 90 181 89
|
||||
3 89 182 88
|
||||
3 88 183 87
|
||||
3 87 184 157
|
||||
3 106 157 156
|
||||
3 108 156 131
|
||||
3 132 108 131
|
||||
3 132 127 108
|
||||
3 132 133 127
|
||||
3 127 133 126
|
||||
3 126 133 134
|
||||
3 125 134 135
|
||||
3 124 135 136
|
||||
3 123 136 137
|
||||
3 122 137 138
|
||||
3 121 138 139
|
||||
3 120 139 140
|
||||
3 141 120 140
|
||||
3 141 119 120
|
||||
3 141 142 119
|
||||
3 119 142 118
|
||||
3 118 142 143
|
||||
3 117 143 144
|
||||
3 116 144 145
|
||||
3 115 145 146
|
||||
3 114 146 147
|
||||
3 113 147 148
|
||||
3 112 148 149
|
||||
3 150 112 149
|
||||
3 150 111 112
|
||||
3 150 151 111
|
||||
3 111 151 110
|
||||
3 110 151 152
|
||||
3 109 152 153
|
||||
3 314 153 154
|
||||
3 155 314 154
|
||||
3 155 315 314
|
||||
3 87 157 106
|
||||
3 128 129 156
|
||||
3 156 129 130
|
||||
3 131 156 130
|
||||
3 126 134 125
|
||||
3 125 135 124
|
||||
3 124 136 123
|
||||
3 123 137 122
|
||||
3 122 138 121
|
||||
3 121 139 120
|
||||
3 118 143 117
|
||||
3 117 144 116
|
||||
3 116 145 115
|
||||
3 115 146 114
|
||||
3 114 147 113
|
||||
3 113 148 112
|
||||
3 110 152 109
|
||||
3 109 153 314
|
||||
3 107 106 108
|
||||
3 108 106 156
|
||||
3 81 82 316
|
||||
3 316 82 83
|
||||
3 313 316 83
|
||||
3 190 293 188
|
||||
3 296 295 297
|
||||
3 299 298 300
|
||||
3 301 302 303
|
||||
3 310 309 304
|
||||
3 304 309 308
|
||||
3 307 304 308
|
||||
3 307 306 304
|
||||
3 304 306 305
|
||||
3 311 304 305
|
||||
3 311 312 304
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
OFF
|
||||
19 9 0
|
||||
|
||||
115.67936706542969 54.544418334960938 16.005954742431641
|
||||
117.02452850341797 55.327865600585938 16.005954742431641
|
||||
117.08579254150391 55.232322692871094 21.716342926025391
|
||||
118.41075134277344 56.176109313964844 18.36799430847168
|
||||
118.40937805175781 56.175144195556641 18.36907958984375
|
||||
118.29840850830078 56.096733093261719 18.45704460144043
|
||||
118.2930908203125 56.092964172363281 18.462148666381836
|
||||
118.28346252441406 56.086151123046875 18.471376419067383
|
||||
118.189697265625 56.019577026367188 18.57948112487793
|
||||
118.18498229980469 56.016223907470703 18.584924697875977
|
||||
117.99317169189453 55.876365661621094 19.02931022644043
|
||||
117.99261474609375 55.875930786132812 19.032327651977539
|
||||
117.98808288574219 55.872333526611328 19.057277679443359
|
||||
117.97309875488281 55.859172821044922 19.2037353515625
|
||||
137.00740051269531 110.97613525390625 65.796310424804688
|
||||
137.4010009765625 109.5654296875 72.631622314453125
|
||||
136.79624938964844 110.9072265625 90.521072387695312
|
||||
117.02452850341797 55.327865600585938 16.005954742431641
|
||||
117.02452850341797 55.327865600585938 16.005954742431641
|
||||
3 0 1 2
|
||||
3 17 3 4
|
||||
3 17 4 5
|
||||
3 5 6 17
|
||||
3 17 6 7
|
||||
3 8 9 17
|
||||
3 18 10 11
|
||||
3 12 13 18
|
||||
3 15 14 16
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
OFF
|
||||
10 4 0
|
||||
|
||||
-67.788215178655193 -78.899037523497398 24.1822920114423
|
||||
-67.788215178655506 -82.368494747405407 20.2941771394655
|
||||
-67.788215178655093 -78.768494747405398 22.3082058185067
|
||||
-67.788215178655193 -78.8606722910787 24.164811049291199
|
||||
-67.788215178655193 -77.913294154982495 23.733142053801899
|
||||
-66.774775293321895 -83.668494747405404 20.2941771394655
|
||||
-66.774775293321895 -87.017787227405407 20.2941771394655
|
||||
-71.262809942886406 -85.979974786270603 20.2941771394655
|
||||
-71.107949314941195 -84.254409627405394 20.2941771394655
|
||||
-71.107949314941195 -83.754409627405394 20.2941771394655
|
||||
3 3 2 4
|
||||
3 4 0 3
|
||||
3 6 1 5
|
||||
3 8 7 9
|
||||
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
OFF
|
||||
131 49 0
|
||||
|
||||
-62.620407104492188 -9.4614181518554688 41.683597564697266
|
||||
-62.620414733886719 -9.4511032104492188 41.735469818115234
|
||||
-62.620414733886719 -9.3767547607421875 41.991233825683594
|
||||
-62.620407104492188 9.4416522979736328 4.5261672312335577e-06
|
||||
-62.620407104492188 -9.4427204132080078 4.5359465730143711e-06
|
||||
-47.809219360351562 3.8510293960571289 1.6157564459717833e-06
|
||||
-62.598831176757812 9.4465980529785156 3.6389292290550657e-06
|
||||
-20.943687438964844 9.3370399475097656 4.2613187360984739e-06
|
||||
-20.914989471435547 9.3493843078613281 4.2757633309520315e-06
|
||||
-20.885889053344727 9.3612480163574219 4.1343832890561316e-06
|
||||
-20.971958160400391 9.3242149353027344 4.4009525481669698e-06
|
||||
20.884809494018555 -9.4510955810546875 125.24068450927734
|
||||
22.457618713378906 9.3619651794433594 6.1448122323781718e-06
|
||||
22.441225051879883 9.3684005737304688 1.7280481188208796e-06
|
||||
21.514957427978516 9.4793128967285156 3.2127923077496234e-06
|
||||
21.498519897460938 9.4772605895996094 3.4301033338124398e-06
|
||||
20.953998565673828 -9.4645252227783203 125.24068450927734
|
||||
20.742733001708984 9.2013893127441406 4.9752002269087825e-06
|
||||
20.766811370849609 9.2175998687744141 5.0692037802946288e-06
|
||||
20.62904167175293 -9.3767471313476562 125.24068450927734
|
||||
20.645746231079102 -9.3829135894775391 125.24068450927734
|
||||
62.620277404785156 -8.7213096618652344 123.39151763916016
|
||||
62.620277404785156 -8.7151603698730469 123.389404296875
|
||||
62.620277404785156 -8.6144905090332031 123.36297607421875
|
||||
62.620277404785156 -8.5096912384033203 123.35044097900391
|
||||
62.620277404785156 -8.5560245513916016 123.35414123535156
|
||||
62.620277404785156 -8.5494556427001953 123.35344696044922
|
||||
62.620277404785156 -8.5230045318603516 123.35118865966797
|
||||
62.620277404785156 -8.6209068298339844 123.36423492431641
|
||||
20.867586135864258 -9.4473285675048828 125.24068450927734
|
||||
20.936674118041992 -9.4614124298095703 125.24068450927734
|
||||
62.620277404785156 -8.5163536071777344 123.35079193115234
|
||||
-51.99945068359375 3.1952471733093262 4.1346197576785926e-06
|
||||
-43.269599914550781 -0.32817482948303223 4.1346211219206452e-06
|
||||
-19.685705184936523 -9.4303531646728516 1.9637736841104925e-06
|
||||
-19.701553344726562 -9.4344139099121094 2.3815769054635894e-06
|
||||
-19.42884635925293 -9.3423709869384766 1.7326274246443063e-06
|
||||
-19.443225860595703 -9.3484916687011719 1.6012136256904341e-06
|
||||
-19.17613410949707 -9.2045211791992188 1.2267801139387302e-06
|
||||
-19.188335418701172 -9.2127552032470703 1.5256782717187889e-06
|
||||
-18.863229751586914 -8.8910446166992188 7.8400080383289605e-07
|
||||
-18.856225967407227 -8.879791259765625 8.6185536929406226e-07
|
||||
22.13054084777832 -9.4565982818603516 2.1357404875743669e-06
|
||||
22.146760940551758 -9.4533329010009766 2.2930016712052748e-06
|
||||
23.093219757080078 -8.848602294921875 7.369217200903222e-07
|
||||
23.08673095703125 -8.8600540161132812 9.480672815698199e-07
|
||||
23.192604064941406 -8.4715385437011719 6.3923471316229552e-07
|
||||
-60.769142150878906 -8.7151699066162109 7.336057024076581e-07
|
||||
-60.74151611328125 -8.6080684661865234 1.4775005183764733e-06
|
||||
-60.742721557617188 -8.6144981384277344 7.0386249717557803e-07
|
||||
-60.735458374023438 -8.5691280364990234 1.0365247362642549e-06
|
||||
-60.73193359375 -8.5362129211425781 7.5862226367462426e-07
|
||||
-60.732528686523438 -8.5428447723388672 1.4881388779031113e-06
|
||||
-60.731399536132812 -8.5296192169189453 9.1052152129122987e-07
|
||||
-60.73016357421875 -8.5097007751464844 6.7293058236828074e-07
|
||||
-60.730514526367188 -8.5163631439208984 1.2532864275272004e-06
|
||||
-60.76708984375 -8.7090129852294922 9.5696577773196623e-07
|
||||
-60.736328125 -8.5756492614746094 6.0640104493359104e-07
|
||||
-60.854118347167969 -8.8915023803710938 8.7522312242072076e-07
|
||||
-60.861328125 -8.9026336669921875 7.8946050052763894e-07
|
||||
-60.729110717773438 -8.4543952941894531 7.1729391493136063e-07
|
||||
-60.876274108886719 -8.9246501922607422 8.3022769103990868e-07
|
||||
-60.883995056152344 -8.9355392456054688 9.3188828031998128e-07
|
||||
-60.729202270507812 -8.4245491027832031 6.4579762693028897e-07
|
||||
-61.030609130859375 -9.0979843139648438 1.1536394595168531e-06
|
||||
-61.041107177734375 -9.1073760986328125 1.031333340506535e-06
|
||||
-61.118423461914062 -9.1705780029296875 1.2765494830091484e-06
|
||||
-61.130058288574219 -9.1792144775390625 1.1604315659496933e-06
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-61.073394775390625 -9.135040283203125 1.2063428584951907e-06
|
||||
-61.084426879882812 -9.1440582275390625 1.098478605854325e-06
|
||||
-61.062492370605469 -9.1259078979492188 1.0930843927781098e-06
|
||||
-61.334144592285156 -9.3026294708251953 1.4496454241452739e-06
|
||||
-61.320480346679688 -9.2956562042236328 1.5968289517331868e-06
|
||||
-61.389518737792969 -9.3292732238769531 1.5349778550444171e-06
|
||||
-61.403656005859375 -9.3356666564941406 1.7014708646456711e-06
|
||||
-61.375503540039062 -9.3227710723876953 1.6700305423000827e-06
|
||||
-61.432220458984375 -9.3480777740478516 1.7529819160699844e-06
|
||||
-61.446647644042969 -9.3541049957275391 1.6125777619890869e-06
|
||||
-61.417877197265625 -9.3419284820556641 1.6077401596703567e-06
|
||||
-61.475830078125 -9.3657875061035156 1.6983394743874669e-06
|
||||
-61.834487915039062 -9.4651222229003906 2.3805814635124989e-06
|
||||
-61.950363159179688 -9.4816017150878906 2.4013088477659039e-06
|
||||
-61.280296325683594 -9.274261474609375 1.3925337043474428e-06
|
||||
-61.611656188964844 -9.4122428894042969 2.077234057651367e-06
|
||||
-61.850944519042969 -9.4679145812988281 2.2724693735654e-06
|
||||
-61.190338134765625 -9.2207355499267578 1.3892249626223929e-06
|
||||
-61.26702880859375 -9.2668933868408203 1.4124379958957434e-06
|
||||
-61.177993774414062 -9.212646484375 1.2388636605464853e-06
|
||||
-61.461189270019531 -9.3600082397460938 1.7946731531992555e-06
|
||||
-61.596229553222656 -9.4075565338134766 1.8849377738661133e-06
|
||||
-61.96710205078125 -9.4833869934082031 2.5995341275120154e-06
|
||||
-60.72930908203125 -0.3698158860206604 5.9438934840727597e-07
|
||||
0.94488376379013062 -8.5163593292236328 61.675388336181641
|
||||
0.94445079565048218 -8.5296249389648438 61.675815582275391
|
||||
62.620277404785156 -8.4543857574462891 123.34938812255859
|
||||
-18.738601684570312 -8.4671974182128906 7.2904640546767041e-07
|
||||
-60.729339599609375 -8.4828910827636719 6.0301135818008333e-07
|
||||
-60.730934143066406 -8.5230140686035156 6.0507500165840611e-07
|
||||
-60.733177185058594 -8.5494670867919922 6.2268281908473e-07
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
20.309930801391602 8.4743385314941406 6.3502930061076768e-06
|
||||
-21.621206283569336 8.4258155822753906 6.0075799410697073e-06
|
||||
-60.72930908203125 6.7186679840087891 2.1500454749912024e-09
|
||||
-60.735458374023438 -8.5691280364990234 1.0365247362642549e-06
|
||||
-60.730514526367188 -8.5163631439208984 1.2532864275272004e-06
|
||||
-60.729110717773438 -8.4543952941894531 7.1729391493136063e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
-60.72930908203125 -8.3959465026855469 5.9263948060106486e-07
|
||||
0.94445079565048218 -8.5296249389648438 61.675815582275391
|
||||
-18.738601684570312 -8.4671974182128906 7.2904640546767041e-07
|
||||
-18.738601684570312 -8.4671974182128906 7.2904640546767041e-07
|
||||
-18.738601684570312 -8.4671974182128906 7.2904640546767041e-07
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
0.94390237331390381 -8.5428562164306641 61.676364898681641
|
||||
20.309930801391602 8.4743385314941406 6.3502930061076768e-06
|
||||
20.309930801391602 8.4743385314941406 6.3502930061076768e-06
|
||||
-21.621206283569336 8.4258155822753906 6.0075799410697073e-06
|
||||
23.192573547363281 -8.4420909881591797 5.9400190366432071e-07
|
||||
3 46 44 45
|
||||
3 50 57 97
|
||||
3 41 40 96
|
||||
3 58 59 60
|
||||
3 55 98 104
|
||||
3 61 62 106
|
||||
3 64 65 63
|
||||
3 66 67 68
|
||||
3 107 69 70
|
||||
3 17 18 101
|
||||
3 38 39 118
|
||||
3 107 71 69
|
||||
3 108 73 72
|
||||
3 109 74 75
|
||||
3 10 7 102
|
||||
3 109 76 74
|
||||
3 77 78 110
|
||||
3 36 37 119
|
||||
3 110 79 77
|
||||
3 8 9 129
|
||||
3 13 12 127
|
||||
3 111 87 83
|
||||
3 89 80 112
|
||||
3 1 11 29
|
||||
3 113 90 84
|
||||
3 34 35 120
|
||||
3 0 16 30
|
||||
3 82 91 114
|
||||
3 88 86 115
|
||||
3 130 43 42
|
||||
3 128 15 14
|
||||
3 116 81 85
|
||||
3 92 4 3
|
||||
3 103 92 3
|
||||
3 103 3 6
|
||||
3 33 32 5
|
||||
3 100 23 28
|
||||
3 49 48 121
|
||||
3 122 22 21
|
||||
3 47 56 123
|
||||
3 124 26 25
|
||||
3 99 52 125
|
||||
3 52 51 125
|
||||
3 125 51 53
|
||||
3 24 31 126
|
||||
3 31 27 126
|
||||
3 94 93 95
|
||||
3 117 105 54
|
||||
3 2 20 19
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
OFF
|
||||
24 10 0
|
||||
|
||||
-22.291719436645508 -33.0625 132.11399841308594
|
||||
-15.280426979064941 -61.062496185302734 132.11399841308594
|
||||
-15.280428886413574 -33.0625 132.11399841308594
|
||||
-6.6061949729919434 -64.0625 119.71333312988281
|
||||
-9.7316780090332031 -16.104564666748047 127.08177185058594
|
||||
-9.7316789627075195 -7.02191162109375 127.08177185058594
|
||||
-9.7316789627075195 -0.72058898210525513 127.08177185058594
|
||||
-9.9586648941040039 -64.0625 126.97700500488281
|
||||
92.889457702636719 7.335627555847168 17.32063102722168
|
||||
92.185699462890625 7.335627555847168 16.567487716674805
|
||||
-23.523859024047852 -39.552497863769531 128.30531311035156
|
||||
-15.280428886413574 -39.552497863769531 128.30531311035156
|
||||
-0.75768494606018066 -61.062496185302734 102.16104888916016
|
||||
-17.72953987121582 -61.062496185302734 138.93341064453125
|
||||
-22.269332885742188 -61.062496185302734 136.83811950683594
|
||||
-19.280878067016602 -36.837699890136719 125.59051513671875
|
||||
-0.75768661499023438 -33.062496185302734 102.16104888916016
|
||||
-17.72953987121582 -33.0625 138.93341064453125
|
||||
-22.26933479309082 -33.0625 136.83811950683594
|
||||
88.691604614257812 7.3356270790100098 14.604374885559082
|
||||
-6.1871428489685059 63.937496185302734 118.80537414550781
|
||||
-6.6062026023864746 63.937496185302734 119.71333312988281
|
||||
-9.9586725234985352 63.937496185302734 126.97700500488281
|
||||
-9.9586648941040039 -64.0625 126.97700500488281
|
||||
3 12 1 13
|
||||
3 13 1 14
|
||||
3 10 15 11
|
||||
3 0 2 18
|
||||
3 8 19 9
|
||||
3 16 12 17
|
||||
3 17 12 13
|
||||
3 3 20 21
|
||||
3 6 22 7
|
||||
3 5 23 4
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
OFF
|
||||
9 3 0
|
||||
|
||||
-22.291719436645508 -33.0625 132.11399841308594
|
||||
-15.280428886413574 -33.0625 132.11399841308594
|
||||
-9.7316780090332031 -16.104564666748047 127.08177185058594
|
||||
-9.7316789627075195 -7.02191162109375 127.08177185058594
|
||||
-0.75768494606018066 -61.062496185302734 102.16104888916016
|
||||
-17.72953987121582 -61.062496185302734 138.93341064453125
|
||||
-17.72953987121582 -33.0625 138.93341064453125
|
||||
-22.26933479309082 -33.0625 136.83811950683594
|
||||
-9.9586648941040039 -64.0625 126.97700500488281
|
||||
3 0 1 7
|
||||
3 6 4 5
|
||||
3 3 8 2
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
OFF
|
||||
36 25 0
|
||||
|
||||
37.944911956787109 -1.6982429027557373 8.5614194869995117
|
||||
38.049285888671875 -1.7218705415725708 8.3133611679077148
|
||||
38.145980834960938 -1.7387760877609253 8.0756645202636719
|
||||
37.676181793212891 -0.08527558296918869 7.889103889465332
|
||||
37.857818603515625 -0.093803025782108307 7.4036040306091309
|
||||
37.735622406005859 -1.6400438547134399 8.8551864624023438
|
||||
37.741683959960938 -1.6386662721633911 8.9242925643920898
|
||||
37.965476989746094 -1.7082259654998779 8.3176441192626953
|
||||
37.98175048828125 -1.7098640203475952 8.3662099838256836
|
||||
38.196575164794922 -1.743979811668396 7.7442541122436523
|
||||
38.217582702636719 -1.747313380241394 7.7797822952270508
|
||||
37.731548309326172 -1.641355037689209 8.799250602722168
|
||||
37.953289031982422 -1.7070465087890625 8.2782869338989258
|
||||
38.180507659912109 -1.7413737773895264 7.7158145904541016
|
||||
38.392875671386719 -1.7514817714691162 7.1327433586120605
|
||||
37.931743621826172 -1.7050290107727051 8.2031984329223633
|
||||
38.151718139648438 -1.73658287525177 7.6619982719421387
|
||||
38.360618591308594 -1.7428750991821289 7.1007680892944336
|
||||
37.916267395019531 -1.7036066055297852 8.1459512710571289
|
||||
38.13104248046875 -1.7330515384674072 7.6210522651672363
|
||||
38.337314605712891 -1.7364044189453125 7.0764865875244141
|
||||
37.69573974609375 -1.6467151641845703 8.4192934036254883
|
||||
37.877265930175781 -1.7001659870147705 7.9938459396362305
|
||||
38.079837799072266 -1.7240269184112549 7.5114293098449707
|
||||
38.279632568359375 -1.7194610834121704 7.0100784301757812
|
||||
37.634693145751953 -1.6362926959991455 8.258021354675293
|
||||
37.667015075683594 -1.6497268676757812 8.1850767135620117
|
||||
37.831775665283203 -1.6966333389282227 7.8121175765991211
|
||||
37.598911285400391 -1.6418465375900269 7.9809689521789551
|
||||
37.62762451171875 -1.6536027193069458 7.9197196960449219
|
||||
37.778202056884766 -1.6935627460479736 7.5982809066772461
|
||||
37.596717834472656 -0.12143304198980331 8.034724235534668
|
||||
37.98175048828125 -1.7098640203475952 8.3662099838256836
|
||||
37.723155975341797 -1.6431630849838257 8.696990966796875
|
||||
37.716129302978516 -1.6441534757614136 8.6208524703979492
|
||||
37.877265930175781 -1.7001659870147705 7.9938459396362305
|
||||
3 4 31 3
|
||||
3 7 8 6
|
||||
3 9 10 8
|
||||
3 9 8 7
|
||||
3 12 7 5
|
||||
3 13 9 7
|
||||
3 13 7 12
|
||||
3 14 9 13
|
||||
3 15 12 11
|
||||
3 16 13 12
|
||||
3 16 12 15
|
||||
3 17 13 16
|
||||
3 18 15 33
|
||||
3 19 16 15
|
||||
3 19 15 18
|
||||
3 20 16 19
|
||||
3 22 34 21
|
||||
3 23 19 18
|
||||
3 23 18 35
|
||||
3 24 19 23
|
||||
3 27 21 26
|
||||
3 29 25 28
|
||||
3 30 27 26
|
||||
3 1 0 32
|
||||
3 8 10 2
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
OFF
|
||||
16 7 0
|
||||
|
||||
29.389250000000001 40.450850000000003 96.239999999999995
|
||||
30.677409000000001 39.162691000000002 12.550000000000001
|
||||
27.766093999999999 41.277892999999999 20.800000000000001
|
||||
30.677409000000001 39.162691000000002 29.050000000000001
|
||||
39.162691000000002 30.677409000000001 29.050000000000001
|
||||
29.389250000000001 40.450850000000003 0
|
||||
30.677409000000001 39.162691000000002 45.549999999999997
|
||||
39.162691000000002 30.677409000000001 45.549999999999997
|
||||
32.798729999999999 37.041370000000001 67.246151999999995
|
||||
30.677409000000001 39.162691000000002 62.049999999999997
|
||||
27.766093999999999 41.277892999999999 53.799999999999997
|
||||
27.766093999999999 41.277892999999999 70.299999999999997
|
||||
25.093077000000001 42.639868999999997 65.103847999999999
|
||||
40.450850000000003 29.389250000000001 96.239999999999995
|
||||
30.677409000000001 39.162691000000002 78.549999999999997
|
||||
27.766093999999999 41.277892999999999 37.299999999999997
|
||||
3 9 14 8
|
||||
3 1 0 3
|
||||
3 3 0 6
|
||||
3 4 7 13
|
||||
3 5 2 0
|
||||
3 15 10 0
|
||||
3 10 12 11
|
||||
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
OFF
|
||||
159 60 0
|
||||
|
||||
-37.902450000000002 27.537749999999999 98.304000000000002
|
||||
-45.549999999999997 0 97.488
|
||||
-40.289050000000003 29.271699999999999 96.959999999999994
|
||||
-48.850000000000001 0 98.016000000000005
|
||||
-47.3626 15.389049999999999 96.959999999999994
|
||||
-49.149999999999999 0 97.775999999999996
|
||||
-46.5 0 98.207999999999998
|
||||
-50 0 96.239999999999995
|
||||
-47.552849999999999 15.450850000000001 96.239999999999995
|
||||
-45.100000000000001 0 96.719999999999999
|
||||
-37.093449999999997 26.949950000000001 97.775999999999996
|
||||
-48.649999999999999 0 98.159999999999997
|
||||
-46.649299999999997 15.157299999999999 97.872
|
||||
-46.744450000000001 15.1882 97.775999999999996
|
||||
-43.177950000000003 14.029350000000001 97.296000000000006
|
||||
-40.369950000000003 29.330500000000001 96.623999999999995
|
||||
-42.892650000000003 13.93665 96.623999999999995
|
||||
-37.700200000000002 27.390799999999999 98.256
|
||||
-44.4619 14.44655 98.304000000000002
|
||||
-44.319249999999997 14.4002 98.256
|
||||
-47.25 0 98.400000000000006
|
||||
-44.937399999999997 14.601050000000001 98.400000000000006
|
||||
-45.412950000000002 14.755549999999999 98.400000000000006
|
||||
-36.729349999999997 26.685449999999999 97.296000000000006
|
||||
-43.60595 14.16845 97.775999999999996
|
||||
-48.950000000000003 0 97.920000000000002
|
||||
-46.554200000000002 15.1264 97.920000000000002
|
||||
-49.649999999999999 0 97.200000000000003
|
||||
-45 0 96.239999999999995
|
||||
-44.557000000000002 14.477449999999999 98.304000000000002
|
||||
-47 0 98.352000000000004
|
||||
-46.850000000000001 0 98.304000000000002
|
||||
-37.255249999999997 27.067499999999999 97.920000000000002
|
||||
-48.399999999999999 0 98.256
|
||||
-36.486649999999997 26.5091 96.623999999999995
|
||||
-43.891249999999999 14.261150000000001 98.016000000000005
|
||||
-39.601399999999998 28.772099999999998 97.920000000000002
|
||||
-38.104700000000001 27.684699999999999 98.352000000000004
|
||||
-45.100000000000001 0 96.623999999999995
|
||||
-42.797550000000001 13.905749999999999 95.760000000000005
|
||||
-46.839550000000003 15.219099999999999 97.680000000000007
|
||||
-49.450000000000003 0 97.488
|
||||
-49.25 0 97.680000000000007
|
||||
-46.149999999999999 0 98.016000000000005
|
||||
-39.358699999999999 28.595749999999999 98.159999999999997
|
||||
-49.049999999999997 0 97.872
|
||||
-47.75 0 98.400000000000006
|
||||
-37.336150000000004 27.126300000000001 98.016000000000005
|
||||
-40.167700000000004 29.18355 97.200000000000003
|
||||
-40.127249999999997 29.154150000000001 97.296000000000006
|
||||
-39.520499999999998 28.7133 98.016000000000005
|
||||
-45.555599999999998 14.8019 98.352000000000004
|
||||
-42.892650000000003 13.93665 96.719999999999999
|
||||
-40.450850000000003 29.389250000000001 96.239999999999995
|
||||
-38.751899999999999 28.154900000000001 98.352000000000004
|
||||
-46.459099999999999 15.095499999999999 98.016000000000005
|
||||
-39.439599999999999 28.65455 98.063999999999993
|
||||
-44.794750000000001 14.5547 98.352000000000004
|
||||
-39.682299999999998 28.830850000000002 97.872
|
||||
-49.950000000000003 0 96.480000000000004
|
||||
-47.505249999999997 15.4354 96.480000000000004
|
||||
-36.405749999999998 26.45035 95.760000000000005
|
||||
-42.797550000000001 13.905749999999999 96.239999999999995
|
||||
-45.049999999999997 0 96.480000000000004
|
||||
-39.763199999999998 28.88965 97.775999999999996
|
||||
-45.75 0 97.680000000000007
|
||||
-36.567549999999997 26.567900000000002 96.959999999999994
|
||||
-36.527099999999997 26.538499999999999 96.864000000000004
|
||||
-45.650700000000001 14.832800000000001 98.352000000000004
|
||||
-48 0 98.352000000000004
|
||||
-47.899999999999999 0 98.352000000000004
|
||||
-37.174349999999997 27.008749999999999 97.872
|
||||
-42.845100000000002 13.921200000000001 96.480000000000004
|
||||
-45.850000000000001 0 97.775999999999996
|
||||
-43.510849999999998 14.137549999999999 97.680000000000007
|
||||
-45.25 0 97.103999999999999
|
||||
-43.035299999999999 13.983000000000001 97.103999999999999
|
||||
-49.850000000000001 0 96.864000000000004
|
||||
-47.410150000000002 15.404500000000001 96.864000000000004
|
||||
-45.888500000000001 14.91005 98.304000000000002
|
||||
-45.793349999999997 14.879149999999999 98.304000000000002
|
||||
-38.630549999999999 28.066749999999999 98.400000000000006
|
||||
-39.844099999999997 28.948399999999999 97.680000000000007
|
||||
-38.226050000000001 27.772849999999998 98.400000000000006
|
||||
-45.950000000000003 0 97.872
|
||||
-49.600000000000001 0 97.296000000000006
|
||||
-40.046349999999997 29.09535 97.391999999999996
|
||||
-48.5 0 98.207999999999998
|
||||
-46.049999999999997 0 97.920000000000002
|
||||
-43.701050000000002 14.199350000000001 97.872
|
||||
-40.410400000000003 29.359850000000002 96.480000000000004
|
||||
-36.446199999999997 26.479749999999999 96.480000000000004
|
||||
-43.796149999999997 14.23025 97.920000000000002
|
||||
-39.156399999999998 28.448799999999999 98.256
|
||||
-46.126249999999999 14.987299999999999 98.207999999999998
|
||||
-46.031149999999997 14.9564 98.256
|
||||
-47.100000000000001 0 98.352000000000004
|
||||
-49.950000000000003 0 96.384
|
||||
-47.505249999999997 15.4354 96.384
|
||||
-44.081449999999997 14.322950000000001 98.159999999999997
|
||||
-40.329500000000003 29.301100000000002 96.864000000000004
|
||||
-38.023800000000001 27.625900000000001 98.352000000000004
|
||||
-44.224150000000002 14.369300000000001 98.207999999999998
|
||||
-42.987749999999998 13.967549999999999 96.959999999999994
|
||||
-45.200000000000003 0 96.959999999999994
|
||||
-47.172400000000003 15.327249999999999 97.296000000000006
|
||||
-49.899999999999999 0 96.623999999999995
|
||||
-37.497950000000003 27.243849999999998 98.159999999999997
|
||||
-37.417050000000003 27.18505 98.063999999999993
|
||||
-46.268900000000002 15.0337 98.159999999999997
|
||||
-48.75 0 98.063999999999993
|
||||
-46.363999999999997 15.0646 98.063999999999993
|
||||
-36.486649999999997 26.5091 96.719999999999999
|
||||
-45 0 95.760000000000005
|
||||
-45.5 0 97.391999999999996
|
||||
-38.832799999999999 28.213699999999999 98.352000000000004
|
||||
-40.248600000000003 29.2423 97.103999999999999
|
||||
-46.25 0 98.063999999999993
|
||||
-36.810250000000003 26.744250000000001 97.391999999999996
|
||||
-38.954149999999998 28.301850000000002 98.304000000000002
|
||||
-47.457700000000003 15.41995 96.719999999999999
|
||||
-47.315049999999999 15.3736 97.103999999999999
|
||||
-40.369950000000003 29.330500000000001 96.719999999999999
|
||||
-37.012549999999997 26.891200000000001 97.680000000000007
|
||||
-36.850700000000003 26.773599999999998 97.488
|
||||
-44.699649999999998 14.5238 98.352000000000004
|
||||
-46.75 0 98.304000000000002
|
||||
-37.619300000000003 27.332000000000001 98.207999999999998
|
||||
-49.799999999999997 0 96.959999999999994
|
||||
-46.600000000000001 0 98.256
|
||||
-43.320599999999999 14.075699999999999 97.488
|
||||
-42.940199999999997 13.9521 96.864000000000004
|
||||
-45.149999999999999 0 96.864000000000004
|
||||
-48.149999999999999 0 98.304000000000002
|
||||
-48.25 0 98.304000000000002
|
||||
-40.410400000000003 29.359850000000002 96.384
|
||||
-37.821550000000002 27.478950000000001 98.304000000000002
|
||||
-47.219949999999997 15.342700000000001 97.200000000000003
|
||||
-45.350000000000001 0 97.200000000000003
|
||||
-43.273049999999998 14.06025 97.391999999999996
|
||||
-39.035049999999998 28.36065 98.304000000000002
|
||||
-45.399999999999999 0 97.296000000000006
|
||||
-43.130400000000002 14.0139 97.200000000000003
|
||||
-49.75 0 97.103999999999999
|
||||
-36.405749999999998 26.45035 96.239999999999995
|
||||
-40.005899999999997 29.065999999999999 97.488
|
||||
-47.02975 15.280900000000001 97.488
|
||||
-36.446199999999997 26.479749999999999 96.384
|
||||
-36.607999999999997 26.597300000000001 97.103999999999999
|
||||
-45.049999999999997 0 96.384
|
||||
-42.845100000000002 13.921200000000001 96.384
|
||||
-47.077300000000001 15.29635 97.391999999999996
|
||||
-49.5 0 97.391999999999996
|
||||
-43.986350000000002 14.29205 98.063999999999993
|
||||
-39.237299999999998 28.5076 98.207999999999998
|
||||
-47.457700000000003 15.41995 96.623999999999995
|
||||
-49.899999999999999 0 96.719999999999999
|
||||
-46.350000000000001 0 98.159999999999997
|
||||
-36.688899999999997 26.65605 97.200000000000003
|
||||
|
||||
|
||||
|
||||
3 124 130 118
|
||||
|
||||
3 89 88 84
|
||||
3 76 138 75
|
||||
|
||||
3 49 137 105
|
||||
3 86 105 151
|
||||
3 131 104 132
|
||||
3 35 117 43
|
||||
3 52 9 16
|
||||
3 92 88 89
|
||||
3 121 128 143
|
||||
3 137 27 105
|
||||
3 103 104 131
|
||||
3 116 4 121
|
||||
3 66 103 67
|
||||
3 112 52 34
|
||||
3 151 152 146
|
||||
3 52 16 34
|
||||
3 57 20 96
|
||||
3 37 57 101
|
||||
3 70 51 68
|
||||
3 56 111 44
|
||||
3 18 126 19
|
||||
3 51 54 68
|
||||
3 130 65 1
|
||||
3 108 99 153
|
||||
3 133 80 79
|
||||
3 39 62 28
|
||||
3 136 18 17
|
||||
3 2 78 4
|
||||
3 127 19 102
|
||||
3 30 125 57
|
||||
3 47 153 35
|
||||
3 120 156 78
|
||||
3 147 150 144
|
||||
3 153 117 35
|
||||
3 151 85 152
|
||||
3 36 26 50
|
||||
3 50 26 55
|
||||
3 0 29 136
|
||||
3 79 134 133
|
||||
3 101 125 0
|
||||
3 10 89 24
|
||||
3 139 1 114
|
||||
3 80 119 79
|
||||
3 107 102 99
|
||||
3 56 55 111
|
||||
3 53 8 135
|
||||
3 154 109 94
|
||||
3 111 3 110
|
||||
3 40 42 13
|
||||
3 98 60 135
|
||||
3 24 84 73
|
||||
3 155 59 106
|
||||
3 60 59 155
|
||||
3 15 60 155
|
||||
3 90 60 15
|
||||
3 68 133 69
|
||||
3 13 42 5
|
||||
3 17 19 127
|
||||
3 14 114 141
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
OFF
|
||||
106 104 0
|
||||
|
||||
-37.902450000000002 27.537749999999999 98.304000000000002
|
||||
-36.688899999999997 26.65605 97.200000000000003
|
||||
-40.289050000000003 29.271699999999999 96.959999999999994
|
||||
-47.457700000000003 15.41995 96.623999999999995
|
||||
-47.3626 15.389049999999999 96.959999999999994
|
||||
-39.237299999999998 28.5076 98.207999999999998
|
||||
-43.986350000000002 14.29205 98.063999999999993
|
||||
-47.077300000000001 15.29635 97.391999999999996
|
||||
-47.552849999999999 15.450850000000001 96.239999999999995
|
||||
-42.845100000000002 13.921200000000001 96.384
|
||||
-37.093449999999997 26.949950000000001 97.775999999999996
|
||||
-36.607999999999997 26.597300000000001 97.103999999999999
|
||||
-46.649299999999997 15.157299999999999 97.872
|
||||
-46.744450000000001 15.1882 97.775999999999996
|
||||
-43.177950000000003 14.029350000000001 97.296000000000006
|
||||
-40.369950000000003 29.330500000000001 96.623999999999995
|
||||
-42.892650000000003 13.93665 96.623999999999995
|
||||
-37.700200000000002 27.390799999999999 98.256
|
||||
-44.4619 14.44655 98.304000000000002
|
||||
-44.319249999999997 14.4002 98.256
|
||||
-36.446199999999997 26.479749999999999 96.384
|
||||
-44.937399999999997 14.601050000000001 98.400000000000006
|
||||
-45.412950000000002 14.755549999999999 98.400000000000006
|
||||
-36.729349999999997 26.685449999999999 97.296000000000006
|
||||
-43.60595 14.16845 97.775999999999996
|
||||
-47.02975 15.280900000000001 97.488
|
||||
-46.554200000000002 15.1264 97.920000000000002
|
||||
-40.005899999999997 29.065999999999999 97.488
|
||||
-36.405749999999998 26.45035 96.239999999999995
|
||||
-44.557000000000002 14.477449999999999 98.304000000000002
|
||||
-43.130400000000002 14.0139 97.200000000000003
|
||||
-39.035049999999998 28.36065 98.304000000000002
|
||||
-37.255249999999997 27.067499999999999 97.920000000000002
|
||||
-43.273049999999998 14.06025 97.391999999999996
|
||||
-36.486649999999997 26.5091 96.623999999999995
|
||||
-43.891249999999999 14.261150000000001 98.016000000000005
|
||||
-39.601399999999998 28.772099999999998 97.920000000000002
|
||||
-38.104700000000001 27.684699999999999 98.352000000000004
|
||||
-47.219949999999997 15.342700000000001 97.200000000000003
|
||||
-42.797550000000001 13.905749999999999 95.760000000000005
|
||||
-46.839550000000003 15.219099999999999 97.680000000000007
|
||||
-37.821550000000002 27.478950000000001 98.304000000000002
|
||||
-40.410400000000003 29.359850000000002 96.384
|
||||
-42.940199999999997 13.9521 96.864000000000004
|
||||
-39.358699999999999 28.595749999999999 98.159999999999997
|
||||
-43.320599999999999 14.075699999999999 97.488
|
||||
-37.619300000000003 27.332000000000001 98.207999999999998
|
||||
-37.336150000000004 27.126300000000001 98.016000000000005
|
||||
-40.167700000000004 29.18355 97.200000000000003
|
||||
-40.127249999999997 29.154150000000001 97.296000000000006
|
||||
-39.520499999999998 28.7133 98.016000000000005
|
||||
-45.555599999999998 14.8019 98.352000000000004
|
||||
-42.892650000000003 13.93665 96.719999999999999
|
||||
-40.450850000000003 29.389250000000001 96.239999999999995
|
||||
-38.751899999999999 28.154900000000001 98.352000000000004
|
||||
-46.459099999999999 15.095499999999999 98.016000000000005
|
||||
-39.439599999999999 28.65455 98.063999999999993
|
||||
-44.794750000000001 14.5547 98.352000000000004
|
||||
-39.682299999999998 28.830850000000002 97.872
|
||||
-44.699649999999998 14.5238 98.352000000000004
|
||||
-47.505249999999997 15.4354 96.480000000000004
|
||||
-36.405749999999998 26.45035 95.760000000000005
|
||||
-42.797550000000001 13.905749999999999 96.239999999999995
|
||||
-36.850700000000003 26.773599999999998 97.488
|
||||
-39.763199999999998 28.88965 97.775999999999996
|
||||
-37.012549999999997 26.891200000000001 97.680000000000007
|
||||
-36.567549999999997 26.567900000000002 96.959999999999994
|
||||
-36.527099999999997 26.538499999999999 96.864000000000004
|
||||
-45.650700000000001 14.832800000000001 98.352000000000004
|
||||
-40.369950000000003 29.330500000000001 96.719999999999999
|
||||
-47.315049999999999 15.3736 97.103999999999999
|
||||
-37.174349999999997 27.008749999999999 97.872
|
||||
-42.845100000000002 13.921200000000001 96.480000000000004
|
||||
-47.457700000000003 15.41995 96.719999999999999
|
||||
-43.510849999999998 14.137549999999999 97.680000000000007
|
||||
-38.954149999999998 28.301850000000002 98.304000000000002
|
||||
-43.035299999999999 13.983000000000001 97.103999999999999
|
||||
-36.810250000000003 26.744250000000001 97.391999999999996
|
||||
-47.410150000000002 15.404500000000001 96.864000000000004
|
||||
-45.888500000000001 14.91005 98.304000000000002
|
||||
-45.793349999999997 14.879149999999999 98.304000000000002
|
||||
-38.630549999999999 28.066749999999999 98.400000000000006
|
||||
-39.844099999999997 28.948399999999999 97.680000000000007
|
||||
-38.226050000000001 27.772849999999998 98.400000000000006
|
||||
-40.248600000000003 29.2423 97.103999999999999
|
||||
-38.832799999999999 28.213699999999999 98.352000000000004
|
||||
-40.046349999999997 29.09535 97.391999999999996
|
||||
-36.486649999999997 26.5091 96.719999999999999
|
||||
-46.363999999999997 15.0646 98.063999999999993
|
||||
-43.701050000000002 14.199350000000001 97.872
|
||||
-40.410400000000003 29.359850000000002 96.480000000000004
|
||||
-36.446199999999997 26.479749999999999 96.480000000000004
|
||||
-43.796149999999997 14.23025 97.920000000000002
|
||||
-39.156399999999998 28.448799999999999 98.256
|
||||
-46.126249999999999 14.987299999999999 98.207999999999998
|
||||
-46.031149999999997 14.9564 98.256
|
||||
-46.268900000000002 15.0337 98.159999999999997
|
||||
-37.417050000000003 27.18505 98.063999999999993
|
||||
-47.505249999999997 15.4354 96.384
|
||||
-44.081449999999997 14.322950000000001 98.159999999999997
|
||||
-40.329500000000003 29.301100000000002 96.864000000000004
|
||||
-38.023800000000001 27.625900000000001 98.352000000000004
|
||||
-44.224150000000002 14.369300000000001 98.207999999999998
|
||||
-42.987749999999998 13.967549999999999 96.959999999999994
|
||||
-37.497950000000003 27.243849999999998 98.159999999999997
|
||||
-47.172400000000003 15.327249999999999 97.296000000000006
|
||||
3 17 19 46
|
||||
3 59 101 57
|
||||
3 90 60 15
|
||||
3 65 74 63
|
||||
3 15 60 3
|
||||
3 84 70 48
|
||||
3 17 18 19
|
||||
3 98 60 42
|
||||
3 5 96 94
|
||||
3 21 83 22
|
||||
3 97 6 47
|
||||
3 53 8 42
|
||||
3 56 55 88
|
||||
3 63 45 77
|
||||
3 93 95 31
|
||||
3 77 33 23
|
||||
3 104 102 99
|
||||
3 80 75 79
|
||||
3 10 89 24
|
||||
3 44 96 5
|
||||
3 67 43 87
|
||||
3 81 22 83
|
||||
3 23 14 1
|
||||
3 75 80 85
|
||||
3 1 30 11
|
||||
3 15 73 69
|
||||
3 44 88 96
|
||||
3 11 30 76
|
||||
3 39 61 62
|
||||
3 37 21 57
|
||||
3 0 59 29
|
||||
3 50 55 56
|
||||
3 77 45 33
|
||||
3 85 80 68
|
||||
3 101 59 0
|
||||
3 31 79 75
|
||||
3 54 51 81
|
||||
3 42 60 90
|
||||
3 0 29 41
|
||||
3 27 7 25
|
||||
3 104 99 97
|
||||
3 48 38 49
|
||||
3 50 26 55
|
||||
3 47 35 32
|
||||
3 32 92 71
|
||||
3 93 94 95
|
||||
3 81 51 22
|
||||
3 11 76 66
|
||||
3 72 9 20
|
||||
3 66 76 103
|
||||
3 36 26 50
|
||||
3 49 38 105
|
||||
3 63 74 45
|
||||
3 64 40 13
|
||||
3 83 21 37
|
||||
3 65 24 74
|
||||
3 18 41 29
|
||||
3 86 105 7
|
||||
3 61 28 62
|
||||
3 58 13 12
|
||||
3 1 14 30
|
||||
3 42 8 98
|
||||
3 82 40 64
|
||||
3 49 105 86
|
||||
3 86 7 27
|
||||
3 67 103 43
|
||||
3 31 95 79
|
||||
3 100 78 2
|
||||
3 91 16 72
|
||||
3 69 73 100
|
||||
3 3 73 15
|
||||
3 85 68 54
|
||||
3 84 4 70
|
||||
3 36 12 26
|
||||
3 87 43 52
|
||||
3 28 9 62
|
||||
3 20 9 28
|
||||
3 48 70 38
|
||||
3 23 33 14
|
||||
3 27 25 82
|
||||
3 5 94 93
|
||||
3 32 35 92
|
||||
3 91 72 20
|
||||
3 66 103 67
|
||||
3 87 52 34
|
||||
3 47 6 35
|
||||
3 52 16 34
|
||||
3 46 19 102
|
||||
3 82 25 40
|
||||
3 2 78 4
|
||||
3 41 18 17
|
||||
3 58 12 36
|
||||
3 2 4 84
|
||||
3 34 16 91
|
||||
3 97 99 6
|
||||
3 46 102 104
|
||||
3 10 24 65
|
||||
3 71 92 89
|
||||
3 64 13 58
|
||||
3 71 89 10
|
||||
3 37 57 101
|
||||
3 100 73 78
|
||||
3 56 88 44
|
||||
3 51 54 68
|
||||
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
OFF
|
||||
71 62 0
|
||||
|
||||
-0.043536998299999997 0.039117999399999999 -0.050000000699999998
|
||||
-0.040624998500000002 0.042913000999999999 -0.050000000699999998
|
||||
0.050000000699999998 0.050000000699999998 -0.050000000699999998
|
||||
-0.041919000400000003 0.016919000100000001 -0.050000000699999998
|
||||
-0.034375000699999998 0.042913000999999999 -0.050000000699999998
|
||||
-0.033080998799999997 0.033080998799999997 -0.050000000699999998
|
||||
-0.043749999300000002 0.0125000002 -0.050000000699999998
|
||||
-0.037500001499999998 -0.043749999300000002 -0.050000000699999998
|
||||
0.014117999900000001 0.031463000900000003 -0.050000000699999998
|
||||
-0.039117999399999999 0.018536999799999999 -0.050000000699999998
|
||||
0.031463000900000003 0.035881999900000003 -0.050000000699999998
|
||||
-0.015625 0.042913000999999999 -0.050000000699999998
|
||||
-0.035881999900000003 0.043536998299999997 -0.050000000699999998
|
||||
-0.043749999300000002 0.037500001499999998 -0.050000000699999998
|
||||
-0.037500001499999998 0.018750000700000002 -0.050000000699999998
|
||||
-0.033080998799999997 0.016919000100000001 -0.050000000699999998
|
||||
-0.041919000400000003 -0.041919000400000003 -0.050000000699999998
|
||||
-0.034375000699999998 0.017913000700000001 -0.050000000699999998
|
||||
-0.018536999799999999 0.039117999399999999 -0.050000000699999998
|
||||
-0.043536998299999997 -0.014117999900000001 -0.050000000699999998
|
||||
-0.031463000900000003 0.035881999900000003 -0.050000000699999998
|
||||
-0.039117999399999999 0.031463000900000003 -0.050000000699999998
|
||||
-0.03125 0.037500001499999998 -0.050000000699999998
|
||||
-0.042913000999999999 0.015625 -0.050000000699999998
|
||||
-0.032086998200000001 0.040624998500000002 -0.050000000699999998
|
||||
-0.039117999399999999 0.043536998299999997 -0.050000000699999998
|
||||
-0.041919000400000003 0.041919000400000003 -0.016919000100000001
|
||||
-0.040624998500000002 0.032086998200000001 -0.050000000699999998
|
||||
-0.0050889999000000002 -0.050000000699999998 -0.050000000699999998
|
||||
-0.018750000700000002 0.037500001499999998 -0.050000000699999998
|
||||
-0.032086998200000001 0.034375000699999998 -0.050000000699999998
|
||||
-0.017913000700000001 0.040624998500000002 -0.050000000699999998
|
||||
-0.016919000100000001 0.033080998799999997 -0.050000000699999998
|
||||
-0.043536998299999997 -0.039117999399999999 -0.050000000699999998
|
||||
0.032086998200000001 0.034375000699999998 -0.050000000699999998
|
||||
-0.043536998299999997 0.014117999900000001 -0.050000000699999998
|
||||
-0.035881999900000003 -0.050000000699999998 -0.043536998299999997
|
||||
0.03125 0.037500001499999998 -0.050000000699999998
|
||||
-0.016919000100000001 0.041919000400000003 -0.050000000699999998
|
||||
-0.043749999300000002 -0.0125000002 -0.050000000699999998
|
||||
-0.014117999900000001 0.043536998299999997 -0.050000000699999998
|
||||
0.015625 0.017913000700000001 -0.050000000699999998
|
||||
-0.037500001499999998 0.03125 -0.050000000699999998
|
||||
-0.034375000699999998 0.032086998200000001 -0.050000000699999998
|
||||
0.014117999900000001 0.018536999799999999 -0.050000000699999998
|
||||
-0.041919000400000003 0.041919000400000003 -0.033080998799999997
|
||||
-0.018536999799999999 0.035881999900000003 -0.050000000699999998
|
||||
-0.042913000999999999 0.034375000699999998 -0.050000000699999998
|
||||
-0.042913000999999999 0.040624998500000002 -0.050000000699999998
|
||||
-0.040624998500000002 -0.042913000999999999 -0.050000000699999998
|
||||
-0.037500001499999998 0.043749999300000002 -0.050000000699999998
|
||||
-0.033080998799999997 0.041919000400000003 -0.050000000699999998
|
||||
-0.041919000400000003 0.041919000400000003 -0.050000000699999998
|
||||
0.018536999799999999 0.035881999900000003 -0.050000000699999998
|
||||
-0.042913000999999999 -0.040624998500000002 -0.050000000699999998
|
||||
0.050000000699999998 0.037500001499999998 -0.043749999300000002
|
||||
-0.035881999900000003 -0.043536998299999997 -0.050000000699999998
|
||||
-0.040972001899999999 0.042697001200000001 -0.0323030017
|
||||
-0.035881999900000003 0.031463000900000003 -0.050000000699999998
|
||||
-0.043536998299999997 -0.035881999900000003 -0.050000000699999998
|
||||
-0.035881999900000003 0.018536999799999999 -0.050000000699999998
|
||||
0.050000000699999998 0.035881999900000003 -0.043536998299999997
|
||||
-0.040624998500000002 0.017913000700000001 -0.050000000699999998
|
||||
-0.043749999300000002 -0.037500001499999998 -0.050000000699999998
|
||||
-0.043536998299999997 0.035881999900000003 -0.050000000699999998
|
||||
-0.031463000900000003 0.039117999399999999 -0.050000000699999998
|
||||
-0.039117999399999999 -0.043536998299999997 -0.050000000699999998
|
||||
-0.050000000699999998 0.050000000699999998 -0.050000000699999998
|
||||
-0.017913000700000001 0.034375000699999998 -0.050000000699999998
|
||||
-0.041919000400000003 0.033080998799999997 -0.050000000699999998
|
||||
-0.050000000699999998 -0.050000000699999998 -0.050000000699999998
|
||||
3 17 5 15
|
||||
3 70 28 36
|
||||
3 44 8 41
|
||||
3 34 53 10
|
||||
3 53 37 10
|
||||
3 30 20 68
|
||||
3 5 30 32
|
||||
3 33 54 70
|
||||
3 33 70 63
|
||||
3 70 59 63
|
||||
3 35 64 47
|
||||
3 12 67 40
|
||||
3 11 51 4
|
||||
3 27 62 3
|
||||
3 67 1 52
|
||||
3 25 1 67
|
||||
3 25 67 50
|
||||
3 67 12 50
|
||||
3 4 12 40
|
||||
3 11 4 40
|
||||
3 48 0 67
|
||||
3 67 6 70
|
||||
3 67 35 6
|
||||
3 64 67 13
|
||||
3 67 0 13
|
||||
3 35 67 64
|
||||
3 23 35 47
|
||||
3 23 47 69
|
||||
3 48 67 52
|
||||
3 70 56 28
|
||||
3 9 27 21
|
||||
3 11 38 51
|
||||
3 20 29 46
|
||||
3 9 42 14
|
||||
3 70 54 16
|
||||
3 49 70 16
|
||||
3 49 66 70
|
||||
3 70 66 7
|
||||
3 56 70 7
|
||||
3 9 21 42
|
||||
3 19 59 70
|
||||
3 19 70 39
|
||||
3 70 6 39
|
||||
3 9 62 27
|
||||
3 23 69 3
|
||||
3 69 27 3
|
||||
3 51 38 31
|
||||
3 24 51 31
|
||||
3 65 24 31
|
||||
3 18 65 31
|
||||
3 18 29 65
|
||||
3 29 20 22
|
||||
3 65 29 22
|
||||
3 26 45 57
|
||||
3 68 20 46
|
||||
3 60 43 17
|
||||
3 17 43 5
|
||||
3 14 42 60
|
||||
3 60 42 58
|
||||
3 43 60 58
|
||||
3 15 5 32
|
||||
3 55 61 2
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
OFF
|
||||
25 12 0
|
||||
|
||||
-0.038718998400000003 0.031369999099999997 -0.018629999800000002
|
||||
-0.038718998400000003 0.031369999099999997 -0.031369999099999997
|
||||
0.015971999600000002 0.017697000899999999 -0.0323030017
|
||||
0.015971999600000002 0.0323030017 -0.0323030017
|
||||
0.016797000499999999 0.0170389991 -0.032930001600000001
|
||||
0.016797000499999999 0.0170389991 -0.0170389991
|
||||
0.016797000499999999 0.0307030007 -0.032930001600000001
|
||||
0.016797000499999999 0.031846001700000001 -0.032841000699999998
|
||||
0.016797000499999999 0.032960999800000002 -0.032575998500000002
|
||||
0.016797000499999999 0.032960999800000002 -0.0170389991
|
||||
0.016919000100000001 0.016919000100000001 -0.033080998799999997
|
||||
0.016919000100000001 0.033080998799999997 -0.033080998799999997
|
||||
0.0170699991 0.016762999800000001 -0.032930001600000001
|
||||
0.017563000299999999 0.033835999700000001 -0.032232001400000002
|
||||
0.017697000899999999 0.017697000899999999 -0.034028001099999997
|
||||
0.017697000899999999 0.0323030017 -0.034028001099999997
|
||||
0.018123999200000001 0.034775000100000002 -0.031706001599999999
|
||||
-0.0398919992 0.031725998999999998 -0.018273999900000001
|
||||
0.032024998200000002 0.034485999500000003 -0.031886998600000001
|
||||
0.0323030017 0.017697000899999999 -0.034028001099999997
|
||||
0.032680001100000002 0.0335219987 -0.032370001099999997
|
||||
0.032930001600000001 0.016762999800000001 -0.032930001600000001
|
||||
0.033236999099999998 0.0307030007 -0.032930001600000001
|
||||
0.033309001499999998 0.031690999900000003 -0.032862998499999997
|
||||
0.033539999299999998 0.032664000999999998 -0.032664000999999998
|
||||
3 22 6 21
|
||||
3 21 6 12
|
||||
3 9 6 7
|
||||
3 6 5 4
|
||||
3 16 13 18
|
||||
3 13 8 20
|
||||
3 8 7 24
|
||||
3 7 6 23
|
||||
3 14 19 10
|
||||
3 17 0 1
|
||||
3 3 11 2
|
||||
3 11 15 10
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
OFF
|
||||
19 7 0
|
||||
|
||||
22.597406387329102 -9.2975788116455078 1.4342140275402926e-06
|
||||
22.583751678466797 -9.3044929504394531 1.8044247553916648e-06
|
||||
22.70263671875 -9.2384414672851562 1.287946361117065e-06
|
||||
22.68988037109375 -9.2462024688720703 1.6323538147844374e-06
|
||||
22.677009582519531 -9.2538528442382812 1.3234302969067357e-06
|
||||
23.117275238037109 -8.8020000457763672 7.0353144110413268e-07
|
||||
23.122810363769531 -8.7901668548583984 7.8837638284312561e-07
|
||||
23.189165115356445 -8.5451927185058594 9.3644030130235478e-07
|
||||
23.183364868164062 -8.5910682678222656 6.0938327806070447e-07
|
||||
23.185302734375 -8.5780525207519531 6.0787260736105964e-07
|
||||
23.184362411499023 -8.5845699310302734 1.4671413737232797e-06
|
||||
23.191577911376953 -8.5120143890380859 6.0525235312525183e-07
|
||||
23.191884994506836 -8.5053310394287109 1.3624994608107954e-06
|
||||
23.167057037353516 -8.6678066253662109 7.1637077780906111e-07
|
||||
23.188507080078125 -8.5517463684082031 6.0315323935355991e-07
|
||||
23.192604064941406 -8.4715385437011719 6.3923471316229552e-07
|
||||
23.167057037353516 -8.6678066253662109 7.1637077780906111e-07
|
||||
23.192573547363281 -8.4420909881591797 5.9400190366432071e-07
|
||||
23.192573547363281 -8.4420909881591797 5.9400190366432071e-07
|
||||
3 9 10 8
|
||||
3 7 14 13
|
||||
3 12 11 16
|
||||
3 3 4 17
|
||||
3 2 3 17
|
||||
3 0 1 18
|
||||
3 15 6 5
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
OFF
|
||||
26 9 0
|
||||
|
||||
-10.02 0 -2.0080200000000001
|
||||
-10 10 10
|
||||
-3.9999799999999999 10.0281 -3.9999799999999999
|
||||
-9.9999199999999995 10.040100000000001 -9.9999199999999995
|
||||
-6.0047800000000002 6.0240600000000004 -10.007999999999999
|
||||
-6.0192600000000001 6.0192600000000001 -6.0192600000000001
|
||||
-5.9999599999999997 10.0321 -5.9999599999999997
|
||||
-5.9999700000000002 10.0281 -3.9999799999999999
|
||||
6.0047899999999998 6.0168400000000002 -4.00319
|
||||
3.9999899999999999 10.012 3.9999899999999999
|
||||
-5.9999900000000004 10.012 3.9999899999999999
|
||||
-6 10 10
|
||||
-6.0047899999999998 6.0192399999999999 4.00319
|
||||
-6.0240600000000004 6.0192699999999997 -10.007999999999999
|
||||
-10.0219 -0.92678099999999997 -0.92678099999999997
|
||||
6.0048000000000004 6.0072099999999997 4.0031999999999996
|
||||
-10.007999999999999 6.0240600000000004 -10.007999999999999
|
||||
-6.0240600000000004 6.0240600000000004 -10.007999999999999
|
||||
5.9999900000000004 10.007999999999999 -3.9999899999999999
|
||||
-10.007999999999999 6.0240600000000004 5.0200500000000003
|
||||
-5.9999599999999997 10.0321 -9.9999400000000005
|
||||
-4.00319 6.0168400000000002 -4.00319
|
||||
-6.0047899999999998 6.0192399999999999 -6.0047899999999998
|
||||
-6.0047899999999998 6.0192399999999999 -4.00319
|
||||
5.9999900000000004 10.007999999999999 3.9999899999999999
|
||||
4.0031999999999996 6.0072099999999997 4.0031999999999996
|
||||
6 23 7 2 18 8 21
|
||||
3 13 17 5
|
||||
4 17 4 22 5
|
||||
6 16 3 20 4 17 13
|
||||
3 3 6 20
|
||||
6 22 4 20 6 7 23
|
||||
6 12 25 15 24 9 10
|
||||
8 1 11 10 9 2 7 6 3
|
||||
6 14 1 3 16 19 0
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
NUM_MAX=${1:-10000}
|
||||
|
||||
|
||||
IDS=$(jq -c "[input_filename, .num_vertices < $NUM_MAX and .solid == 1]" json/* | awk -F'[/.,]' '/,true/ { print $2 }')
|
||||
pushd solid-max_10k_vertices > /dev/null
|
||||
for i in $IDS; do
|
||||
ln -s ../raw_meshes/$i.* ./
|
||||
done
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/autorefinement.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/IO/polygon_soup_io.h>
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const std::string filename = argc == 1 ? CGAL::data_file_path("meshes/elephant.off")
|
||||
: std::string(argv[1]);
|
||||
|
||||
std::vector<Point> input_points;
|
||||
std::vector<boost::container::small_vector<std::size_t, 3>> input_triangles;
|
||||
if (!CGAL::IO::read_polygon_soup(filename, input_points, input_triangles))
|
||||
{
|
||||
std::cerr << "Cannot read " << filename << "\n";
|
||||
return 1;
|
||||
}
|
||||
PMP::repair_polygon_soup(input_points, input_triangles);
|
||||
PMP::triangulate_polygons(input_points, input_triangles);
|
||||
|
||||
CGAL::Real_timer t;
|
||||
t.start();
|
||||
PMP::autorefine_triangle_soup(input_points, input_triangles,
|
||||
CGAL::parameters::concurrency_tag(CGAL::Parallel_if_available_tag())
|
||||
/* .apply_iterative_snap_rounding(true) */);
|
||||
t.stop();
|
||||
std::cout << "#points = " << input_points.size() << " and #triangles = " << input_triangles.size() << " in " << t.time() << " sec." << std::endl;
|
||||
// CGAL::IO::write_polygon_soup("autorefined.off", input_points, input_triangles, CGAL::parameters::stream_precision(17));
|
||||
|
||||
|
||||
#if 1
|
||||
PMP::orient_polygon_soup(input_points, input_triangles);
|
||||
|
||||
CGAL::Surface_mesh<Kernel::Point_3> mesh;
|
||||
PMP::polygon_soup_to_polygon_mesh(input_points, input_triangles, mesh);
|
||||
PMP::remove_almost_degenerate_faces(mesh);
|
||||
|
||||
input_points.clear();
|
||||
input_triangles.clear();
|
||||
PMP::polygon_mesh_to_polygon_soup(mesh, input_points, input_triangles);
|
||||
#endif
|
||||
|
||||
t.reset();
|
||||
t.start();
|
||||
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(input_points, input_triangles);\
|
||||
t.stop();
|
||||
|
||||
std::cout << "call to CDT3 done in " << t.time() << " sec." << std::endl;
|
||||
|
||||
return ccdt.triangulation().dimension() == 3 ? 0 : 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/boost/graph/Euler_operations.h>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point = K::Point_3;
|
||||
using PolygonMesh = CGAL::Surface_mesh<Point>;
|
||||
using vertex_descriptor = PolygonMesh::Vertex_index;
|
||||
|
||||
int main()
|
||||
{
|
||||
const std::array<Point, 4> points{ {
|
||||
{0., 0., 0.},
|
||||
{1., 0., 0.},
|
||||
{1., 1., 0.},
|
||||
{0., 1., 0.}
|
||||
} };
|
||||
const std::array<std::array<std::size_t, 4>, 1> polygons{ {
|
||||
{0, 1, 2, 3}
|
||||
} };
|
||||
std::array<vertex_descriptor, 4> vertices;
|
||||
PolygonMesh mesh;
|
||||
std::transform(points.begin(), points.end(), vertices.begin(),
|
||||
[&mesh](const Point& p) { return mesh.add_vertex(p); });
|
||||
|
||||
[[maybe_unused]] auto fd = CGAL::Euler::add_face(vertices, mesh);
|
||||
assert(CGAL::is_valid_polygon_mesh(mesh));
|
||||
|
||||
auto cdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh);
|
||||
assert(cdt.is_valid());
|
||||
assert(cdt.constrained_facets().size() == 2);
|
||||
|
||||
cdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(points, polygons);
|
||||
assert(cdt.is_valid());
|
||||
assert(cdt.constrained_facets().size() == 2);
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h>
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_cell_base_3.h>
|
||||
|
||||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/tetrahedral_remeshing.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
|
||||
using Vbb = CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3<K>;
|
||||
using Vb = CGAL::Conforming_constrained_Delaunay_triangulation_vertex_base_3<K, Vbb>;
|
||||
|
||||
using Cbb = CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3<K>;
|
||||
using Cb = CGAL::Conforming_constrained_Delaunay_triangulation_cell_base_3<K, Cbb>;
|
||||
|
||||
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
|
||||
using Tr = CGAL::Triangulation_3<K, Tds>;
|
||||
using CDT = CGAL::Conforming_constrained_Delaunay_triangulation_3<K, Tr>;
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
|
||||
std::ifstream in(filename);
|
||||
if(!in || !CGAL::IO::read_OFF(in, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " faces" << std::endl;
|
||||
|
||||
auto cdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3<CDT>(mesh);
|
||||
static_assert(std::is_same_v<decltype(cdt), CDT>);
|
||||
CDT cdt2(mesh);
|
||||
const auto nb_cstr_facets = cdt2.number_of_constrained_facets();
|
||||
|
||||
assert(cdt.triangulation().number_of_vertices() == cdt2.triangulation().number_of_vertices());
|
||||
assert(cdt.number_of_constrained_facets() == cdt2.number_of_constrained_facets());
|
||||
assert(cdt.number_of_constrained_facets() > mesh.num_faces());
|
||||
|
||||
namespace Tet_remesh = CGAL::Tetrahedral_remeshing;
|
||||
Tr tr = Tet_remesh::get_remeshing_triangulation(std::move(cdt));
|
||||
|
||||
CGAL::tetrahedral_isotropic_remeshing(tr, 2.,
|
||||
CGAL::parameters::number_of_iterations(3)
|
||||
.remesh_boundaries(false));
|
||||
|
||||
std::cout << "Number of vertices in tr: " << tr.number_of_vertices() << std::endl;
|
||||
|
||||
auto nb = 0u;
|
||||
for(auto f : tr.finite_facets())
|
||||
{
|
||||
const Tr::Cell_handle c = f.first;
|
||||
const int i = f.second;
|
||||
if(c->is_facet_on_surface(i))
|
||||
++nb;
|
||||
}
|
||||
assert(nb == nb_cstr_facets);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Conforming_constrained_Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using CDT = CGAL::Conforming_constrained_Delaunay_triangulation_3<K>;
|
||||
|
||||
static_assert(CGAL::cdt_3_msvc_2019_or_older() || CGAL::is_nothrow_movable_v<CDT>);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CGAL::Surface_mesh<K::Point_3> mesh;
|
||||
auto filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/mpi.off");
|
||||
std::ifstream in(filename);
|
||||
if(!in || !CGAL::IO::read_OFF(in, mesh)) {
|
||||
std::cerr << "Error: cannot read file " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Read " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " faces" << std::endl;
|
||||
|
||||
auto cdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3<CDT>(mesh);
|
||||
static_assert(std::is_same_v<decltype(cdt), CDT>);
|
||||
CDT cdt2(mesh);
|
||||
const auto nb_cstr_facets = cdt2.number_of_constrained_facets();
|
||||
|
||||
assert(cdt.triangulation().number_of_vertices() == cdt2.triangulation().number_of_vertices());
|
||||
assert(cdt.number_of_constrained_facets() == cdt2.number_of_constrained_facets());
|
||||
assert(cdt.number_of_constrained_facets() > mesh.num_faces());
|
||||
|
||||
auto tr = std::move(cdt).triangulation();
|
||||
assert(0 == cdt.triangulation().number_of_vertices());
|
||||
assert(tr.number_of_vertices() == cdt2.triangulation().number_of_vertices());
|
||||
|
||||
std::size_t nb = 0;
|
||||
for([[maybe_unused]] auto _ : cdt2.constrained_facets()) {
|
||||
++nb;
|
||||
}
|
||||
assert(nb == nb_cstr_facets);
|
||||
int dist = static_cast<int>(std::distance(cdt2.constrained_facets_begin(),
|
||||
cdt2.constrained_facets_end()));
|
||||
assert(dist >= 0);
|
||||
assert(dist == static_cast<int>(nb));
|
||||
}
|
||||